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