1//===--- VariantValue.cpp - Polymorphic value type --------------*- 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/// \file
10/// Polymorphic value type.
11///
12//===----------------------------------------------------------------------===//
13
14#include "clang/ASTMatchers/Dynamic/VariantValue.h"
15#include "clang/Basic/LLVM.h"
16#include <optional>
17
18namespace clang {
19namespace ast_matchers {
20namespace dynamic {
21
22std::string ArgKind::asString() const {
23 switch (getArgKind()) {
24 case AK_Matcher:
25 return (Twine("Matcher<") + NodeKind.asStringRef() + ">").str();
26 case AK_Node:
27 return NodeKind.asStringRef().str();
28 case AK_Boolean:
29 return "boolean";
30 case AK_Double:
31 return "double";
32 case AK_Unsigned:
33 return "unsigned";
34 case AK_String:
35 return "string";
36 }
37 llvm_unreachable("unhandled ArgKind");
38}
39
40bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const {
41 if (K != To.K)
42 return false;
43 if (K != AK_Matcher && K != AK_Node) {
44 if (Specificity)
45 *Specificity = 1;
46 return true;
47 }
48 unsigned Distance;
49 if (!NodeKind.isBaseOf(Other: To.NodeKind, Distance: &Distance))
50 return false;
51
52 if (Specificity)
53 *Specificity = 100 - Distance;
54 return true;
55}
56
57bool
58VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher,
59 bool &IsExactMatch) const {
60 IsExactMatch = Matcher.getSupportedKind().isSame(Other: NodeKind);
61 return Matcher.canConvertTo(To: NodeKind);
62}
63
64DynTypedMatcher VariantMatcher::MatcherOps::convertMatcher(
65 const DynTypedMatcher &Matcher) const {
66 return Matcher.dynCastTo(Kind: NodeKind);
67}
68
69std::optional<DynTypedMatcher>
70VariantMatcher::MatcherOps::constructVariadicOperator(
71 DynTypedMatcher::VariadicOperator Op,
72 ArrayRef<VariantMatcher> InnerMatchers) const {
73 std::vector<DynTypedMatcher> DynMatchers;
74 for (const auto &InnerMatcher : InnerMatchers) {
75 // Abort if any of the inner matchers can't be converted to
76 // Matcher<T>.
77 if (!InnerMatcher.Value)
78 return std::nullopt;
79 std::optional<DynTypedMatcher> Inner =
80 InnerMatcher.Value->getTypedMatcher(Ops: *this);
81 if (!Inner)
82 return std::nullopt;
83 DynMatchers.push_back(x: *Inner);
84 }
85 return DynTypedMatcher::constructVariadic(Op, SupportedKind: NodeKind, InnerMatchers: DynMatchers);
86}
87
88VariantMatcher::Payload::~Payload() {}
89
90class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
91public:
92 SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
93
94 std::optional<DynTypedMatcher> getSingleMatcher() const override {
95 return Matcher;
96 }
97
98 std::string getTypeAsString() const override {
99 return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
100 .str();
101 }
102
103 std::optional<DynTypedMatcher>
104 getTypedMatcher(const MatcherOps &Ops) const override {
105 bool Ignore;
106 if (Ops.canConstructFrom(Matcher, IsExactMatch&: Ignore))
107 return Matcher;
108 return std::nullopt;
109 }
110
111 bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
112 return ArgKind::MakeMatcherArg(MatcherKind: Matcher.getSupportedKind())
113 .isConvertibleTo(To: ArgKind::MakeMatcherArg(MatcherKind: Kind), Specificity);
114 }
115
116private:
117 const DynTypedMatcher Matcher;
118};
119
120class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
121public:
122 PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)
123 : Matchers(std::move(MatchersIn)) {}
124
125 ~PolymorphicPayload() override {}
126
127 std::optional<DynTypedMatcher> getSingleMatcher() const override {
128 if (Matchers.size() != 1)
129 return std::nullopt;
130 return Matchers[0];
131 }
132
133 std::string getTypeAsString() const override {
134 std::string Inner;
135 for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
136 if (i != 0)
137 Inner += "|";
138 Inner += Matchers[i].getSupportedKind().asStringRef();
139 }
140 return (Twine("Matcher<") + Inner + ">").str();
141 }
142
143 std::optional<DynTypedMatcher>
144 getTypedMatcher(const MatcherOps &Ops) const override {
145 bool FoundIsExact = false;
146 const DynTypedMatcher *Found = nullptr;
147 int NumFound = 0;
148 for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
149 bool IsExactMatch;
150 if (Ops.canConstructFrom(Matcher: Matchers[i], IsExactMatch)) {
151 if (Found) {
152 if (FoundIsExact) {
153 assert(!IsExactMatch && "We should not have two exact matches.");
154 continue;
155 }
156 }
157 Found = &Matchers[i];
158 FoundIsExact = IsExactMatch;
159 ++NumFound;
160 }
161 }
162 // We only succeed if we found exactly one, or if we found an exact match.
163 if (Found && (FoundIsExact || NumFound == 1))
164 return *Found;
165 return std::nullopt;
166 }
167
168 bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
169 unsigned MaxSpecificity = 0;
170 for (const DynTypedMatcher &Matcher : Matchers) {
171 unsigned ThisSpecificity;
172 if (ArgKind::MakeMatcherArg(MatcherKind: Matcher.getSupportedKind())
173 .isConvertibleTo(To: ArgKind::MakeMatcherArg(MatcherKind: Kind),
174 Specificity: &ThisSpecificity)) {
175 MaxSpecificity = std::max(a: MaxSpecificity, b: ThisSpecificity);
176 }
177 }
178 if (Specificity)
179 *Specificity = MaxSpecificity;
180 return MaxSpecificity > 0;
181 }
182
183 const std::vector<DynTypedMatcher> Matchers;
184};
185
186class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
187public:
188 VariadicOpPayload(DynTypedMatcher::VariadicOperator Op,
189 std::vector<VariantMatcher> Args)
190 : Op(Op), Args(std::move(Args)) {}
191
192 std::optional<DynTypedMatcher> getSingleMatcher() const override {
193 return std::nullopt;
194 }
195
196 std::string getTypeAsString() const override {
197 std::string Inner;
198 for (size_t i = 0, e = Args.size(); i != e; ++i) {
199 if (i != 0)
200 Inner += "&";
201 Inner += Args[i].getTypeAsString();
202 }
203 return Inner;
204 }
205
206 std::optional<DynTypedMatcher>
207 getTypedMatcher(const MatcherOps &Ops) const override {
208 return Ops.constructVariadicOperator(Op, InnerMatchers: Args);
209 }
210
211 bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
212 for (const VariantMatcher &Matcher : Args) {
213 if (!Matcher.isConvertibleTo(Kind, Specificity))
214 return false;
215 }
216 return true;
217 }
218
219private:
220 const DynTypedMatcher::VariadicOperator Op;
221 const std::vector<VariantMatcher> Args;
222};
223
224VariantMatcher::VariantMatcher() {}
225
226VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
227 return VariantMatcher(std::make_shared<SinglePayload>(args: Matcher));
228}
229
230VariantMatcher
231VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {
232 return VariantMatcher(
233 std::make_shared<PolymorphicPayload>(args: std::move(Matchers)));
234}
235
236VariantMatcher VariantMatcher::VariadicOperatorMatcher(
237 DynTypedMatcher::VariadicOperator Op,
238 std::vector<VariantMatcher> Args) {
239 return VariantMatcher(
240 std::make_shared<VariadicOpPayload>(args&: Op, args: std::move(Args)));
241}
242
243std::optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
244 return Value ? Value->getSingleMatcher() : std::optional<DynTypedMatcher>();
245}
246
247void VariantMatcher::reset() { Value.reset(); }
248
249std::string VariantMatcher::getTypeAsString() const {
250 if (Value) return Value->getTypeAsString();
251 return "<Nothing>";
252}
253
254VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
255 *this = Other;
256}
257
258VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {
259 setBoolean(Boolean);
260}
261
262VariantValue::VariantValue(double Double) : Type(VT_Nothing) {
263 setDouble(Double);
264}
265
266VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
267 setUnsigned(Unsigned);
268}
269
270VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) {
271 setString(String);
272}
273
274VariantValue::VariantValue(ASTNodeKind NodeKind) : Type(VT_Nothing) {
275 setNodeKind(NodeKind);
276}
277
278VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) {
279 setMatcher(Matcher);
280}
281
282VariantValue::~VariantValue() { reset(); }
283
284VariantValue &VariantValue::operator=(const VariantValue &Other) {
285 if (this == &Other) return *this;
286 reset();
287 switch (Other.Type) {
288 case VT_Boolean:
289 setBoolean(Other.getBoolean());
290 break;
291 case VT_Double:
292 setDouble(Other.getDouble());
293 break;
294 case VT_Unsigned:
295 setUnsigned(Other.getUnsigned());
296 break;
297 case VT_String:
298 setString(Other.getString());
299 break;
300 case VT_NodeKind:
301 setNodeKind(Other.getNodeKind());
302 break;
303 case VT_Matcher:
304 setMatcher(Other.getMatcher());
305 break;
306 case VT_Nothing:
307 Type = VT_Nothing;
308 break;
309 }
310 return *this;
311}
312
313void VariantValue::reset() {
314 switch (Type) {
315 case VT_String:
316 delete Value.String;
317 break;
318 case VT_Matcher:
319 delete Value.Matcher;
320 break;
321 case VT_NodeKind:
322 delete Value.NodeKind;
323 break;
324 // Cases that do nothing.
325 case VT_Boolean:
326 case VT_Double:
327 case VT_Unsigned:
328 case VT_Nothing:
329 break;
330 }
331 Type = VT_Nothing;
332}
333
334bool VariantValue::isBoolean() const {
335 return Type == VT_Boolean;
336}
337
338bool VariantValue::getBoolean() const {
339 assert(isBoolean());
340 return Value.Boolean;
341}
342
343void VariantValue::setBoolean(bool NewValue) {
344 reset();
345 Type = VT_Boolean;
346 Value.Boolean = NewValue;
347}
348
349bool VariantValue::isDouble() const {
350 return Type == VT_Double;
351}
352
353double VariantValue::getDouble() const {
354 assert(isDouble());
355 return Value.Double;
356}
357
358void VariantValue::setDouble(double NewValue) {
359 reset();
360 Type = VT_Double;
361 Value.Double = NewValue;
362}
363
364bool VariantValue::isUnsigned() const {
365 return Type == VT_Unsigned;
366}
367
368unsigned VariantValue::getUnsigned() const {
369 assert(isUnsigned());
370 return Value.Unsigned;
371}
372
373void VariantValue::setUnsigned(unsigned NewValue) {
374 reset();
375 Type = VT_Unsigned;
376 Value.Unsigned = NewValue;
377}
378
379bool VariantValue::isString() const {
380 return Type == VT_String;
381}
382
383const std::string &VariantValue::getString() const {
384 assert(isString());
385 return *Value.String;
386}
387
388void VariantValue::setString(StringRef NewValue) {
389 reset();
390 Type = VT_String;
391 Value.String = new std::string(NewValue);
392}
393
394bool VariantValue::isNodeKind() const { return Type == VT_NodeKind; }
395
396const ASTNodeKind &VariantValue::getNodeKind() const {
397 assert(isNodeKind());
398 return *Value.NodeKind;
399}
400
401void VariantValue::setNodeKind(ASTNodeKind NewValue) {
402 reset();
403 Type = VT_NodeKind;
404 Value.NodeKind = new ASTNodeKind(NewValue);
405}
406
407bool VariantValue::isMatcher() const {
408 return Type == VT_Matcher;
409}
410
411const VariantMatcher &VariantValue::getMatcher() const {
412 assert(isMatcher());
413 return *Value.Matcher;
414}
415
416void VariantValue::setMatcher(const VariantMatcher &NewValue) {
417 reset();
418 Type = VT_Matcher;
419 Value.Matcher = new VariantMatcher(NewValue);
420}
421
422bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
423 switch (Kind.getArgKind()) {
424 case ArgKind::AK_Boolean:
425 if (!isBoolean())
426 return false;
427 *Specificity = 1;
428 return true;
429
430 case ArgKind::AK_Double:
431 if (!isDouble())
432 return false;
433 *Specificity = 1;
434 return true;
435
436 case ArgKind::AK_Unsigned:
437 if (!isUnsigned())
438 return false;
439 *Specificity = 1;
440 return true;
441
442 case ArgKind::AK_String:
443 if (!isString())
444 return false;
445 *Specificity = 1;
446 return true;
447
448 case ArgKind::AK_Node:
449 if (!isNodeKind())
450 return false;
451 return getMatcher().isConvertibleTo(Kind: Kind.getNodeKind(), Specificity);
452
453 case ArgKind::AK_Matcher:
454 if (!isMatcher())
455 return false;
456 return getMatcher().isConvertibleTo(Kind: Kind.getMatcherKind(), Specificity);
457 }
458 llvm_unreachable("Invalid Type");
459}
460
461bool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds,
462 unsigned *Specificity) const {
463 unsigned MaxSpecificity = 0;
464 for (const ArgKind& Kind : Kinds) {
465 unsigned ThisSpecificity;
466 if (!isConvertibleTo(Kind, Specificity: &ThisSpecificity))
467 continue;
468 MaxSpecificity = std::max(a: MaxSpecificity, b: ThisSpecificity);
469 }
470 if (Specificity && MaxSpecificity > 0) {
471 *Specificity = MaxSpecificity;
472 }
473 return MaxSpecificity > 0;
474}
475
476std::string VariantValue::getTypeAsString() const {
477 switch (Type) {
478 case VT_String: return "String";
479 case VT_Matcher: return getMatcher().getTypeAsString();
480 case VT_Boolean: return "Boolean";
481 case VT_Double: return "Double";
482 case VT_Unsigned: return "Unsigned";
483 case VT_NodeKind:
484 return getNodeKind().asStringRef().str();
485 case VT_Nothing: return "Nothing";
486 }
487 llvm_unreachable("Invalid Type");
488}
489
490} // end namespace dynamic
491} // end namespace ast_matchers
492} // end namespace clang
493

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/lib/ASTMatchers/Dynamic/VariantValue.cpp