1 //===--- Marshallers.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Marshallers.h" 10 #include "llvm/ADT/ArrayRef.h" 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/Support/Regex.h" 13 #include <optional> 14 #include <string> 15 16 static std::optional<std::string> 17 getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed, 18 llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) { 19 if (MaxEditDistance != ~0U) 20 ++MaxEditDistance; 21 llvm::StringRef Res; 22 for (const llvm::StringRef &Item : Allowed) { 23 if (Item.equals_insensitive(Search)) { 24 assert(!Item.equals(Search) && "This should be handled earlier on."); 25 MaxEditDistance = 1; 26 Res = Item; 27 continue; 28 } 29 unsigned Distance = Item.edit_distance(Search); 30 if (Distance < MaxEditDistance) { 31 MaxEditDistance = Distance; 32 Res = Item; 33 } 34 } 35 if (!Res.empty()) 36 return Res.str(); 37 if (!DropPrefix.empty()) { 38 --MaxEditDistance; // Treat dropping the prefix as 1 edit 39 for (const llvm::StringRef &Item : Allowed) { 40 auto NoPrefix = Item; 41 if (!NoPrefix.consume_front(DropPrefix)) 42 continue; 43 if (NoPrefix.equals_insensitive(Search)) { 44 if (NoPrefix.equals(Search)) 45 return Item.str(); 46 MaxEditDistance = 1; 47 Res = Item; 48 continue; 49 } 50 unsigned Distance = NoPrefix.edit_distance(Search); 51 if (Distance < MaxEditDistance) { 52 MaxEditDistance = Distance; 53 Res = Item; 54 } 55 } 56 if (!Res.empty()) 57 return Res.str(); 58 } 59 return std::nullopt; 60 } 61 62 std::optional<std::string> 63 clang::ast_matchers::dynamic::internal::ArgTypeTraits< 64 clang::attr::Kind>::getBestGuess(const VariantValue &Value) { 65 static constexpr llvm::StringRef Allowed[] = { 66 #define ATTR(X) "attr::" #X, 67 #include "clang/Basic/AttrList.inc" 68 }; 69 if (Value.isString()) 70 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "attr::"); 71 return std::nullopt; 72 } 73 74 std::optional<std::string> 75 clang::ast_matchers::dynamic::internal::ArgTypeTraits< 76 clang::CastKind>::getBestGuess(const VariantValue &Value) { 77 static constexpr llvm::StringRef Allowed[] = { 78 #define CAST_OPERATION(Name) "CK_" #Name, 79 #include "clang/AST/OperationKinds.def" 80 }; 81 if (Value.isString()) 82 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "CK_"); 83 return std::nullopt; 84 } 85 86 std::optional<std::string> 87 clang::ast_matchers::dynamic::internal::ArgTypeTraits< 88 clang::OpenMPClauseKind>::getBestGuess(const VariantValue &Value) { 89 static constexpr llvm::StringRef Allowed[] = { 90 #define GEN_CLANG_CLAUSE_CLASS 91 #define CLAUSE_CLASS(Enum, Str, Class) #Enum, 92 #include "llvm/Frontend/OpenMP/OMP.inc" 93 }; 94 if (Value.isString()) 95 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "OMPC_"); 96 return std::nullopt; 97 } 98 99 std::optional<std::string> 100 clang::ast_matchers::dynamic::internal::ArgTypeTraits< 101 clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) { 102 static constexpr llvm::StringRef Allowed[] = { 103 #define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, 104 #define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, 105 #include "clang/Basic/TokenKinds.def" 106 }; 107 if (Value.isString()) 108 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "UETT_"); 109 return std::nullopt; 110 } 111 112 static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags> 113 RegexMap[] = { 114 {"NoFlags", llvm::Regex::RegexFlags::NoFlags}, 115 {"IgnoreCase", llvm::Regex::RegexFlags::IgnoreCase}, 116 {"Newline", llvm::Regex::RegexFlags::Newline}, 117 {"BasicRegex", llvm::Regex::RegexFlags::BasicRegex}, 118 }; 119 120 static std::optional<llvm::Regex::RegexFlags> 121 getRegexFlag(llvm::StringRef Flag) { 122 for (const auto &StringFlag : RegexMap) { 123 if (Flag == StringFlag.first) 124 return StringFlag.second; 125 } 126 return std::nullopt; 127 } 128 129 static std::optional<llvm::StringRef> getCloseRegexMatch(llvm::StringRef Flag) { 130 for (const auto &StringFlag : RegexMap) { 131 if (Flag.edit_distance(StringFlag.first) < 3) 132 return StringFlag.first; 133 } 134 return std::nullopt; 135 } 136 137 std::optional<llvm::Regex::RegexFlags> 138 clang::ast_matchers::dynamic::internal::ArgTypeTraits< 139 llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) { 140 std::optional<llvm::Regex::RegexFlags> Flag; 141 SmallVector<StringRef, 4> Split; 142 Flags.split(Split, '|', -1, false); 143 for (StringRef OrFlag : Split) { 144 if (std::optional<llvm::Regex::RegexFlags> NextFlag = 145 getRegexFlag(OrFlag.trim())) 146 Flag = Flag.value_or(llvm::Regex::NoFlags) | *NextFlag; 147 else 148 return std::nullopt; 149 } 150 return Flag; 151 } 152 153 std::optional<std::string> 154 clang::ast_matchers::dynamic::internal::ArgTypeTraits< 155 llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) { 156 if (!Value.isString()) 157 return std::nullopt; 158 SmallVector<StringRef, 4> Split; 159 llvm::StringRef(Value.getString()).split(Split, '|', -1, false); 160 for (llvm::StringRef &Flag : Split) { 161 if (std::optional<llvm::StringRef> BestGuess = 162 getCloseRegexMatch(Flag.trim())) 163 Flag = *BestGuess; 164 else 165 return std::nullopt; 166 } 167 if (Split.empty()) 168 return std::nullopt; 169 return llvm::join(Split, " | "); 170 } 171