clang 24.0.0git
Marshallers.cpp
Go to the documentation of this file.
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
17
20 Diagnostics *Error) const {
21 std::vector<ast_matchers::internal::DynTypedMatcher> InnerMatchers;
22 InnerMatchers.reserve(Args.size());
23 for (size_t I = 0; I != Args.size(); ++I) {
24 const ParserValue &Arg = Args[I];
25 if (!Arg.Value.isMatcher() ||
26 !Arg.Value.getMatcher().hasTypedMatcher(DerivedKind)) {
27 Error->addError(Arg.Range, Error->ET_RegistryWrongArgType)
28 << (I + 1) << ArgKind::MakeMatcherArg(DerivedKind).asString()
29 << Arg.Value.getTypeAsString();
30 return {};
31 }
32 InnerMatchers.push_back(Arg.Value.getMatcher()
33 .getTypedMatcher(DerivedKind)
34 .dynCastTo(DerivedKind));
35 }
36
37 ast_matchers::internal::DynTypedMatcher Result =
38 InnerMatchers.empty()
39 ? ast_matchers::internal::DynTypedMatcher::trueMatcher(DerivedKind)
40 : InnerMatchers.size() == 1
41 ? InnerMatchers.front()
42 : ast_matchers::internal::DynTypedMatcher::constructVariadic(
43 ast_matchers::internal::DynTypedMatcher::VO_AllOf, DerivedKind,
44 std::move(InnerMatchers));
45 Result = Result.dynCastTo(BaseKind);
46 Result.setAllowBind(true);
48}
49
51 ASTNodeKind Kind, unsigned *Specificity,
52 ASTNodeKind *LeastDerivedKind) const {
53 if (!isRetKindConvertibleTo(ArrayRef(BaseKind), Kind, Specificity,
54 LeastDerivedKind))
55 return false;
56
57 // If Kind is not a base of DerivedKind, either DerivedKind is a base of Kind
58 // (in which case the match will always succeed) or Kind and DerivedKind are
59 // unrelated (in which case it will always fail), so set Specificity to 0.
60 if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) {
61 if (Specificity)
62 *Specificity = 0;
63 }
64 return true;
65}
66
67} // namespace clang::ast_matchers::dynamic::internal
68
69static std::optional<std::string>
70getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed,
71 llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) {
72 if (MaxEditDistance != ~0U)
73 ++MaxEditDistance;
74 llvm::StringRef Res;
75 for (const llvm::StringRef &Item : Allowed) {
76 if (Item.equals_insensitive(Search)) {
77 assert(Item != Search && "This should be handled earlier on.");
78 MaxEditDistance = 1;
79 Res = Item;
80 continue;
81 }
82 unsigned Distance = Item.edit_distance(Search);
83 if (Distance < MaxEditDistance) {
84 MaxEditDistance = Distance;
85 Res = Item;
86 }
87 }
88 if (!Res.empty())
89 return Res.str();
90 if (!DropPrefix.empty()) {
91 --MaxEditDistance; // Treat dropping the prefix as 1 edit
92 for (const llvm::StringRef &Item : Allowed) {
93 auto NoPrefix = Item;
94 if (!NoPrefix.consume_front(DropPrefix))
95 continue;
96 if (NoPrefix.equals_insensitive(Search)) {
97 if (NoPrefix == Search)
98 return Item.str();
99 MaxEditDistance = 1;
100 Res = Item;
101 continue;
102 }
103 unsigned Distance = NoPrefix.edit_distance(Search);
104 if (Distance < MaxEditDistance) {
105 MaxEditDistance = Distance;
106 Res = Item;
107 }
108 }
109 if (!Res.empty())
110 return Res.str();
111 }
112 return std::nullopt;
113}
114
115std::optional<std::string>
116clang::ast_matchers::dynamic::internal::ArgTypeTraits<
118 static constexpr llvm::StringRef Allowed[] = {
119#define ATTR(X) "attr::" #X,
120#include "clang/Basic/AttrList.inc"
121 };
122 if (Value.isString())
123 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "attr::");
124 return std::nullopt;
125}
126
127std::optional<std::string>
128clang::ast_matchers::dynamic::internal::ArgTypeTraits<
130 static constexpr llvm::StringRef Allowed[] = {
131#define CAST_OPERATION(Name) "CK_" #Name,
132#include "clang/AST/OperationKinds.def"
133 };
134 if (Value.isString())
135 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "CK_");
136 return std::nullopt;
137}
138
139std::optional<std::string>
140clang::ast_matchers::dynamic::internal::ArgTypeTraits<
142 static constexpr llvm::StringRef Allowed[] = {
143#define GEN_CLANG_CLAUSE_CLASS
144#define CLAUSE_CLASS(Enum, Str, Class) #Enum,
145#include "llvm/Frontend/OpenMP/OMP.inc"
146 };
147 if (Value.isString())
148 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "OMPC_");
149 return std::nullopt;
150}
151
152std::optional<std::string>
153clang::ast_matchers::dynamic::internal::ArgTypeTraits<
154 clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) {
155 static constexpr llvm::StringRef Allowed[] = {
156#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
157#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
158#include "clang/Basic/BuiltinTraits.inc"
159 };
160 if (Value.isString())
161 return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "UETT_");
162 return std::nullopt;
163}
164
165static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags>
167 {"NoFlags", llvm::Regex::RegexFlags::NoFlags},
168 {"IgnoreCase", llvm::Regex::RegexFlags::IgnoreCase},
169 {"Newline", llvm::Regex::RegexFlags::Newline},
170 {"BasicRegex", llvm::Regex::RegexFlags::BasicRegex},
171};
172
173static std::optional<llvm::Regex::RegexFlags>
174getRegexFlag(llvm::StringRef Flag) {
175 for (const auto &StringFlag : RegexMap) {
176 if (Flag == StringFlag.first)
177 return StringFlag.second;
178 }
179 return std::nullopt;
180}
181
182static std::optional<llvm::StringRef> getCloseRegexMatch(llvm::StringRef Flag) {
183 for (const auto &StringFlag : RegexMap) {
184 if (Flag.edit_distance(StringFlag.first) < 3)
185 return StringFlag.first;
186 }
187 return std::nullopt;
188}
189
190std::optional<llvm::Regex::RegexFlags>
191clang::ast_matchers::dynamic::internal::ArgTypeTraits<
192 llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) {
193 std::optional<llvm::Regex::RegexFlags> Flag;
194 SmallVector<StringRef, 4> Split;
195 Flags.split(Split, '|', -1, false);
196 for (StringRef OrFlag : Split) {
197 if (std::optional<llvm::Regex::RegexFlags> NextFlag =
198 getRegexFlag(OrFlag.trim()))
199 Flag = Flag.value_or(llvm::Regex::NoFlags) | *NextFlag;
200 else
201 return std::nullopt;
202 }
203 return Flag;
204}
205
206std::optional<std::string>
207clang::ast_matchers::dynamic::internal::ArgTypeTraits<
208 llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) {
209 if (!Value.isString())
210 return std::nullopt;
212 llvm::StringRef(Value.getString()).split(Split, '|', -1, false);
213 for (llvm::StringRef &Flag : Split) {
214 if (std::optional<llvm::StringRef> BestGuess =
215 getCloseRegexMatch(Flag.trim()))
216 Flag = *BestGuess;
217 else
218 return std::nullopt;
219 }
220 if (Split.empty())
221 return std::nullopt;
222 return llvm::join(Split, " | ");
223}
static std::optional< llvm::StringRef > getCloseRegexMatch(llvm::StringRef Flag)
static constexpr std::pair< llvm::StringRef, llvm::Regex::RegexFlags > RegexMap[]
static std::optional< llvm::Regex::RegexFlags > getRegexFlag(llvm::StringRef Flag)
static std::optional< std::string > getBestGuess(llvm::StringRef Search, llvm::ArrayRef< llvm::StringRef > Allowed, llvm::StringRef DropPrefix="", unsigned MaxEditDistance=3)
Functions templates and classes to wrap matcher construct functions.
Kind identifier.
static ArgKind MakeMatcherArg(ASTNodeKind MatcherKind)
Constructor for matcher types.
Helper class to manage error messages.
Definition Diagnostics.h:50
ast_matchers::internal::Matcher< T > getTypedMatcher() const
Return this matcher as a Matcher<T>.
bool hasTypedMatcher() const
Determines if the contained matcher can be converted to Matcher<T>.
static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher)
Clones the provided matcher.
std::string getTypeAsString() const
String representation of the type of the value.
const VariantMatcher & getMatcher() const
bool isMatcher() const
Matcher value functions.
VariantMatcher create(SourceRange NameRange, ArrayRef< ParserValue > Args, Diagnostics *Error) const override
bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, ASTNodeKind *LeastDerivedKind) const override
Returns whether this matcher is convertible to the given type.
bool isRetKindConvertibleTo(ArrayRef< ASTNodeKind > RetKinds, ASTNodeKind Kind, unsigned *Specificity, ASTNodeKind *LeastDerivedKind)
@ Result
The result type of a method or function.
Definition TypeBase.h:906
CastKind
CastKind - The kind of operation required for a conversion.
llvm::omp::Clause OpenMPClauseKind
OpenMP clauses.
Definition OpenMPKinds.h:28
A VariantValue instance annotated with its parser context.
Definition Diagnostics.h:42