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/Optional.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/Support/Regex.h"
14 #include <string>
15
16 static llvm::Optional<std::string>
getBestGuess(llvm::StringRef Search,llvm::ArrayRef<llvm::StringRef> Allowed,llvm::StringRef DropPrefix="",unsigned MaxEditDistance=3)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_lower(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_lower(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 llvm::None;
60 }
61
62 llvm::Optional<std::string>
63 clang::ast_matchers::dynamic::internal::ArgTypeTraits<
getBestGuess(const VariantValue & Value)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::makeArrayRef(Allowed),
71 "attr::");
72 return llvm::None;
73 }
74
75 llvm::Optional<std::string>
76 clang::ast_matchers::dynamic::internal::ArgTypeTraits<
getBestGuess(const VariantValue & Value)77 clang::CastKind>::getBestGuess(const VariantValue &Value) {
78 static constexpr llvm::StringRef Allowed[] = {
79 #define CAST_OPERATION(Name) "CK_" #Name,
80 #include "clang/AST/OperationKinds.def"
81 };
82 if (Value.isString())
83 return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
84 "CK_");
85 return llvm::None;
86 }
87
88 llvm::Optional<std::string>
89 clang::ast_matchers::dynamic::internal::ArgTypeTraits<
getBestGuess(const VariantValue & Value)90 clang::OpenMPClauseKind>::getBestGuess(const VariantValue &Value) {
91 static constexpr llvm::StringRef Allowed[] = {
92 #define OMP_CLAUSE_CLASS(Enum, Str, Class) #Enum,
93 #include "llvm/Frontend/OpenMP/OMPKinds.def"
94 };
95 if (Value.isString())
96 return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
97 "OMPC_");
98 return llvm::None;
99 }
100
101 llvm::Optional<std::string>
102 clang::ast_matchers::dynamic::internal::ArgTypeTraits<
getBestGuess(const VariantValue & Value)103 clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) {
104 static constexpr llvm::StringRef Allowed[] = {
105 #define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
106 #define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
107 #include "clang/Basic/TokenKinds.def"
108 };
109 if (Value.isString())
110 return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
111 "UETT_");
112 return llvm::None;
113 }
114
115 static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags>
116 RegexMap[] = {
117 {"NoFlags", llvm::Regex::RegexFlags::NoFlags},
118 {"IgnoreCase", llvm::Regex::RegexFlags::IgnoreCase},
119 {"Newline", llvm::Regex::RegexFlags::Newline},
120 {"BasicRegex", llvm::Regex::RegexFlags::BasicRegex},
121 };
122
123 static llvm::Optional<llvm::Regex::RegexFlags>
getRegexFlag(llvm::StringRef Flag)124 getRegexFlag(llvm::StringRef Flag) {
125 for (const auto &StringFlag : RegexMap) {
126 if (Flag == StringFlag.first)
127 return StringFlag.second;
128 }
129 return llvm::None;
130 }
131
132 static llvm::Optional<llvm::StringRef>
getCloseRegexMatch(llvm::StringRef Flag)133 getCloseRegexMatch(llvm::StringRef Flag) {
134 for (const auto &StringFlag : RegexMap) {
135 if (Flag.edit_distance(StringFlag.first) < 3)
136 return StringFlag.first;
137 }
138 return llvm::None;
139 }
140
141 llvm::Optional<llvm::Regex::RegexFlags>
142 clang::ast_matchers::dynamic::internal::ArgTypeTraits<
getFlags(llvm::StringRef Flags)143 llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) {
144 llvm::Optional<llvm::Regex::RegexFlags> Flag;
145 SmallVector<StringRef, 4> Split;
146 Flags.split(Split, '|', -1, false);
147 for (StringRef OrFlag : Split) {
148 if (llvm::Optional<llvm::Regex::RegexFlags> NextFlag =
149 getRegexFlag(OrFlag.trim()))
150 Flag = Flag.getValueOr(llvm::Regex::NoFlags) | *NextFlag;
151 else
152 return None;
153 }
154 return Flag;
155 }
156
157 llvm::Optional<std::string>
158 clang::ast_matchers::dynamic::internal::ArgTypeTraits<
getBestGuess(const VariantValue & Value)159 llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) {
160 if (!Value.isString())
161 return llvm::None;
162 SmallVector<StringRef, 4> Split;
163 llvm::StringRef(Value.getString()).split(Split, '|', -1, false);
164 for (llvm::StringRef &Flag : Split) {
165 if (llvm::Optional<llvm::StringRef> BestGuess =
166 getCloseRegexMatch(Flag.trim()))
167 Flag = *BestGuess;
168 else
169 return None;
170 }
171 if (Split.empty())
172 return None;
173 return llvm::join(Split, " | ");
174 }
175