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 | |
18 | namespace clang { |
19 | namespace ast_matchers { |
20 | namespace dynamic { |
21 | |
22 | std::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 | |
40 | bool 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 | |
57 | bool |
58 | VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, |
59 | bool &IsExactMatch) const { |
60 | IsExactMatch = Matcher.getSupportedKind().isSame(Other: NodeKind); |
61 | return Matcher.canConvertTo(To: NodeKind); |
62 | } |
63 | |
64 | DynTypedMatcher VariantMatcher::MatcherOps::convertMatcher( |
65 | const DynTypedMatcher &Matcher) const { |
66 | return Matcher.dynCastTo(Kind: NodeKind); |
67 | } |
68 | |
69 | std::optional<DynTypedMatcher> |
70 | VariantMatcher::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 | |
88 | VariantMatcher::Payload::~Payload() {} |
89 | |
90 | class VariantMatcher::SinglePayload : public VariantMatcher::Payload { |
91 | public: |
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 | |
116 | private: |
117 | const DynTypedMatcher Matcher; |
118 | }; |
119 | |
120 | class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload { |
121 | public: |
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 | |
186 | class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { |
187 | public: |
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 | |
219 | private: |
220 | const DynTypedMatcher::VariadicOperator Op; |
221 | const std::vector<VariantMatcher> Args; |
222 | }; |
223 | |
224 | VariantMatcher::VariantMatcher() {} |
225 | |
226 | VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { |
227 | return VariantMatcher(std::make_shared<SinglePayload>(args: Matcher)); |
228 | } |
229 | |
230 | VariantMatcher |
231 | VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) { |
232 | return VariantMatcher( |
233 | std::make_shared<PolymorphicPayload>(args: std::move(Matchers))); |
234 | } |
235 | |
236 | VariantMatcher 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 | |
243 | std::optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const { |
244 | return Value ? Value->getSingleMatcher() : std::optional<DynTypedMatcher>(); |
245 | } |
246 | |
247 | void VariantMatcher::reset() { Value.reset(); } |
248 | |
249 | std::string VariantMatcher::getTypeAsString() const { |
250 | if (Value) return Value->getTypeAsString(); |
251 | return "<Nothing>"; |
252 | } |
253 | |
254 | VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { |
255 | *this = Other; |
256 | } |
257 | |
258 | VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) { |
259 | setBoolean(Boolean); |
260 | } |
261 | |
262 | VariantValue::VariantValue(double Double) : Type(VT_Nothing) { |
263 | setDouble(Double); |
264 | } |
265 | |
266 | VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { |
267 | setUnsigned(Unsigned); |
268 | } |
269 | |
270 | VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) { |
271 | setString(String); |
272 | } |
273 | |
274 | VariantValue::VariantValue(ASTNodeKind NodeKind) : Type(VT_Nothing) { |
275 | setNodeKind(NodeKind); |
276 | } |
277 | |
278 | VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) { |
279 | setMatcher(Matcher); |
280 | } |
281 | |
282 | VariantValue::~VariantValue() { reset(); } |
283 | |
284 | VariantValue &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 | |
313 | void 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 | |
334 | bool VariantValue::isBoolean() const { |
335 | return Type == VT_Boolean; |
336 | } |
337 | |
338 | bool VariantValue::getBoolean() const { |
339 | assert(isBoolean()); |
340 | return Value.Boolean; |
341 | } |
342 | |
343 | void VariantValue::setBoolean(bool NewValue) { |
344 | reset(); |
345 | Type = VT_Boolean; |
346 | Value.Boolean = NewValue; |
347 | } |
348 | |
349 | bool VariantValue::isDouble() const { |
350 | return Type == VT_Double; |
351 | } |
352 | |
353 | double VariantValue::getDouble() const { |
354 | assert(isDouble()); |
355 | return Value.Double; |
356 | } |
357 | |
358 | void VariantValue::setDouble(double NewValue) { |
359 | reset(); |
360 | Type = VT_Double; |
361 | Value.Double = NewValue; |
362 | } |
363 | |
364 | bool VariantValue::isUnsigned() const { |
365 | return Type == VT_Unsigned; |
366 | } |
367 | |
368 | unsigned VariantValue::getUnsigned() const { |
369 | assert(isUnsigned()); |
370 | return Value.Unsigned; |
371 | } |
372 | |
373 | void VariantValue::setUnsigned(unsigned NewValue) { |
374 | reset(); |
375 | Type = VT_Unsigned; |
376 | Value.Unsigned = NewValue; |
377 | } |
378 | |
379 | bool VariantValue::isString() const { |
380 | return Type == VT_String; |
381 | } |
382 | |
383 | const std::string &VariantValue::getString() const { |
384 | assert(isString()); |
385 | return *Value.String; |
386 | } |
387 | |
388 | void VariantValue::setString(StringRef NewValue) { |
389 | reset(); |
390 | Type = VT_String; |
391 | Value.String = new std::string(NewValue); |
392 | } |
393 | |
394 | bool VariantValue::isNodeKind() const { return Type == VT_NodeKind; } |
395 | |
396 | const ASTNodeKind &VariantValue::getNodeKind() const { |
397 | assert(isNodeKind()); |
398 | return *Value.NodeKind; |
399 | } |
400 | |
401 | void VariantValue::setNodeKind(ASTNodeKind NewValue) { |
402 | reset(); |
403 | Type = VT_NodeKind; |
404 | Value.NodeKind = new ASTNodeKind(NewValue); |
405 | } |
406 | |
407 | bool VariantValue::isMatcher() const { |
408 | return Type == VT_Matcher; |
409 | } |
410 | |
411 | const VariantMatcher &VariantValue::getMatcher() const { |
412 | assert(isMatcher()); |
413 | return *Value.Matcher; |
414 | } |
415 | |
416 | void VariantValue::setMatcher(const VariantMatcher &NewValue) { |
417 | reset(); |
418 | Type = VT_Matcher; |
419 | Value.Matcher = new VariantMatcher(NewValue); |
420 | } |
421 | |
422 | bool 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 | |
461 | bool 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 | |
476 | std::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 |
Definitions
- asString
- isConvertibleTo
- canConstructFrom
- convertMatcher
- constructVariadicOperator
- ~Payload
- SinglePayload
- SinglePayload
- getSingleMatcher
- getTypeAsString
- getTypedMatcher
- isConvertibleTo
- PolymorphicPayload
- PolymorphicPayload
- ~PolymorphicPayload
- getSingleMatcher
- getTypeAsString
- getTypedMatcher
- isConvertibleTo
- VariadicOpPayload
- VariadicOpPayload
- getSingleMatcher
- getTypeAsString
- getTypedMatcher
- isConvertibleTo
- VariantMatcher
- SingleMatcher
- PolymorphicMatcher
- VariadicOperatorMatcher
- getSingleMatcher
- reset
- getTypeAsString
- VariantValue
- VariantValue
- VariantValue
- VariantValue
- VariantValue
- VariantValue
- VariantValue
- ~VariantValue
- operator=
- reset
- isBoolean
- getBoolean
- setBoolean
- isDouble
- getDouble
- setDouble
- isUnsigned
- getUnsigned
- setUnsigned
- isString
- getString
- setString
- isNodeKind
- getNodeKind
- setNodeKind
- isMatcher
- getMatcher
- setMatcher
- isConvertibleTo
- isConvertibleTo
Improve your Profiling and Debugging skills
Find out more