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(RHS: Search)) { |
24 | assert(Item != Search && "This should be handled earlier on." ); |
25 | MaxEditDistance = 1; |
26 | Res = Item; |
27 | continue; |
28 | } |
29 | unsigned Distance = Item.edit_distance(Other: 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(Prefix: DropPrefix)) |
42 | continue; |
43 | if (NoPrefix.equals_insensitive(RHS: Search)) { |
44 | if (NoPrefix == Search) |
45 | return Item.str(); |
46 | MaxEditDistance = 1; |
47 | Res = Item; |
48 | continue; |
49 | } |
50 | unsigned Distance = NoPrefix.edit_distance(Other: 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(Search: Value.getString(), Allowed: llvm::ArrayRef(Allowed), DropPrefix: "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(Search: Value.getString(), Allowed: llvm::ArrayRef(Allowed), DropPrefix: "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(Search: Value.getString(), Allowed: llvm::ArrayRef(Allowed), DropPrefix: "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(Search: Value.getString(), Allowed: llvm::ArrayRef(Allowed), DropPrefix: "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(Other: 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(A&: Split, Separator: '|', MaxSplit: -1, KeepEmpty: false); |
143 | for (StringRef OrFlag : Split) { |
144 | if (std::optional<llvm::Regex::RegexFlags> NextFlag = |
145 | getRegexFlag(Flag: OrFlag.trim())) |
146 | Flag = Flag.value_or(u: 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(A&: Split, Separator: '|', MaxSplit: -1, KeepEmpty: false); |
160 | for (llvm::StringRef &Flag : Split) { |
161 | if (std::optional<llvm::StringRef> BestGuess = |
162 | getCloseRegexMatch(Flag: Flag.trim())) |
163 | Flag = *BestGuess; |
164 | else |
165 | return std::nullopt; |
166 | } |
167 | if (Split.empty()) |
168 | return std::nullopt; |
169 | return llvm::join(R&: Split, Separator: " | " ); |
170 | } |
171 | |