VariantValue.cpp revision 321369
1259701Sdim//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/
2259701Sdim//
3259701Sdim//                     The LLVM Compiler Infrastructure
4259701Sdim//
5259701Sdim// This file is distributed under the University of Illinois Open Source
6259701Sdim// License. See LICENSE.TXT for details.
7259701Sdim//
8259701Sdim//===----------------------------------------------------------------------===//
9259701Sdim///
10259701Sdim/// \file
11259701Sdim/// \brief Polymorphic value type.
12259701Sdim///
13259701Sdim//===----------------------------------------------------------------------===//
14259701Sdim
15259701Sdim#include "clang/ASTMatchers/Dynamic/VariantValue.h"
16259701Sdim#include "clang/Basic/LLVM.h"
17259701Sdim#include "llvm/ADT/STLExtras.h"
18259701Sdim
19259701Sdimnamespace clang {
20259701Sdimnamespace ast_matchers {
21259701Sdimnamespace dynamic {
22259701Sdim
23280031Sdimstd::string ArgKind::asString() const {
24280031Sdim  switch (getArgKind()) {
25280031Sdim  case AK_Matcher:
26280031Sdim    return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
27321369Sdim  case AK_Boolean:
28321369Sdim    return "boolean";
29321369Sdim  case AK_Double:
30321369Sdim    return "double";
31280031Sdim  case AK_Unsigned:
32280031Sdim    return "unsigned";
33280031Sdim  case AK_String:
34280031Sdim    return "string";
35280031Sdim  }
36280031Sdim  llvm_unreachable("unhandled ArgKind");
37280031Sdim}
38280031Sdim
39280031Sdimbool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const {
40280031Sdim  if (K != To.K)
41280031Sdim    return false;
42280031Sdim  if (K != AK_Matcher) {
43280031Sdim    if (Specificity)
44280031Sdim      *Specificity = 1;
45280031Sdim    return true;
46280031Sdim  }
47280031Sdim  unsigned Distance;
48280031Sdim  if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance))
49280031Sdim    return false;
50280031Sdim
51280031Sdim  if (Specificity)
52280031Sdim    *Specificity = 100 - Distance;
53280031Sdim  return true;
54280031Sdim}
55280031Sdim
56280031Sdimbool
57280031SdimVariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher,
58280031Sdim                                             bool &IsExactMatch) const {
59280031Sdim  IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind);
60280031Sdim  return Matcher.canConvertTo(NodeKind);
61280031Sdim}
62280031Sdim
63280031Sdimllvm::Optional<DynTypedMatcher>
64280031SdimVariantMatcher::MatcherOps::constructVariadicOperator(
65280031Sdim    DynTypedMatcher::VariadicOperator Op,
66280031Sdim    ArrayRef<VariantMatcher> InnerMatchers) const {
67280031Sdim  std::vector<DynTypedMatcher> DynMatchers;
68280031Sdim  for (const auto &InnerMatcher : InnerMatchers) {
69280031Sdim    // Abort if any of the inner matchers can't be converted to
70280031Sdim    // Matcher<T>.
71280031Sdim    if (!InnerMatcher.Value)
72280031Sdim      return llvm::None;
73280031Sdim    llvm::Optional<DynTypedMatcher> Inner =
74280031Sdim        InnerMatcher.Value->getTypedMatcher(*this);
75280031Sdim    if (!Inner)
76280031Sdim      return llvm::None;
77280031Sdim    DynMatchers.push_back(*Inner);
78280031Sdim  }
79296417Sdim  return DynTypedMatcher::constructVariadic(Op, NodeKind, DynMatchers);
80280031Sdim}
81280031Sdim
82259701SdimVariantMatcher::Payload::~Payload() {}
83259701Sdim
84259701Sdimclass VariantMatcher::SinglePayload : public VariantMatcher::Payload {
85259701Sdimpublic:
86259701Sdim  SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
87259701Sdim
88280031Sdim  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
89259701Sdim    return Matcher;
90259701Sdim  }
91259701Sdim
92280031Sdim  std::string getTypeAsString() const override {
93259701Sdim    return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
94259701Sdim        .str();
95259701Sdim  }
96259701Sdim
97280031Sdim  llvm::Optional<DynTypedMatcher>
98280031Sdim  getTypedMatcher(const MatcherOps &Ops) const override {
99276479Sdim    bool Ignore;
100276479Sdim    if (Ops.canConstructFrom(Matcher, Ignore))
101280031Sdim      return Matcher;
102280031Sdim    return llvm::None;
103259701Sdim  }
104259701Sdim
105280031Sdim  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
106280031Sdim                       unsigned *Specificity) const override {
107280031Sdim    return ArgKind(Matcher.getSupportedKind())
108280031Sdim        .isConvertibleTo(Kind, Specificity);
109280031Sdim  }
110280031Sdim
111259701Sdimprivate:
112259701Sdim  const DynTypedMatcher Matcher;
113259701Sdim};
114259701Sdim
115259701Sdimclass VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
116259701Sdimpublic:
117276479Sdim  PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)
118276479Sdim      : Matchers(std::move(MatchersIn)) {}
119259701Sdim
120280031Sdim  ~PolymorphicPayload() override {}
121259701Sdim
122280031Sdim  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
123259701Sdim    if (Matchers.size() != 1)
124259701Sdim      return llvm::Optional<DynTypedMatcher>();
125259701Sdim    return Matchers[0];
126259701Sdim  }
127259701Sdim
128280031Sdim  std::string getTypeAsString() const override {
129259701Sdim    std::string Inner;
130259701Sdim    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
131259701Sdim      if (i != 0)
132259701Sdim        Inner += "|";
133259701Sdim      Inner += Matchers[i].getSupportedKind().asStringRef();
134259701Sdim    }
135259701Sdim    return (Twine("Matcher<") + Inner + ">").str();
136259701Sdim  }
137259701Sdim
138280031Sdim  llvm::Optional<DynTypedMatcher>
139280031Sdim  getTypedMatcher(const MatcherOps &Ops) const override {
140276479Sdim    bool FoundIsExact = false;
141276479Sdim    const DynTypedMatcher *Found = nullptr;
142276479Sdim    int NumFound = 0;
143259701Sdim    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
144276479Sdim      bool IsExactMatch;
145276479Sdim      if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) {
146276479Sdim        if (Found) {
147276479Sdim          if (FoundIsExact) {
148276479Sdim            assert(!IsExactMatch && "We should not have two exact matches.");
149276479Sdim            continue;
150276479Sdim          }
151276479Sdim        }
152259701Sdim        Found = &Matchers[i];
153276479Sdim        FoundIsExact = IsExactMatch;
154276479Sdim        ++NumFound;
155259701Sdim      }
156259701Sdim    }
157276479Sdim    // We only succeed if we found exactly one, or if we found an exact match.
158276479Sdim    if (Found && (FoundIsExact || NumFound == 1))
159280031Sdim      return *Found;
160280031Sdim    return llvm::None;
161259701Sdim  }
162259701Sdim
163280031Sdim  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
164280031Sdim                       unsigned *Specificity) const override {
165280031Sdim    unsigned MaxSpecificity = 0;
166280031Sdim    for (const DynTypedMatcher &Matcher : Matchers) {
167280031Sdim      unsigned ThisSpecificity;
168280031Sdim      if (ArgKind(Matcher.getSupportedKind())
169280031Sdim              .isConvertibleTo(Kind, &ThisSpecificity)) {
170280031Sdim        MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);
171280031Sdim      }
172280031Sdim    }
173280031Sdim    if (Specificity)
174280031Sdim      *Specificity = MaxSpecificity;
175280031Sdim    return MaxSpecificity > 0;
176280031Sdim  }
177280031Sdim
178259701Sdim  const std::vector<DynTypedMatcher> Matchers;
179259701Sdim};
180259701Sdim
181259701Sdimclass VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
182259701Sdimpublic:
183280031Sdim  VariadicOpPayload(DynTypedMatcher::VariadicOperator Op,
184276479Sdim                    std::vector<VariantMatcher> Args)
185280031Sdim      : Op(Op), Args(std::move(Args)) {}
186259701Sdim
187280031Sdim  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
188259701Sdim    return llvm::Optional<DynTypedMatcher>();
189259701Sdim  }
190259701Sdim
191280031Sdim  std::string getTypeAsString() const override {
192259701Sdim    std::string Inner;
193259701Sdim    for (size_t i = 0, e = Args.size(); i != e; ++i) {
194259701Sdim      if (i != 0)
195259701Sdim        Inner += "&";
196259701Sdim      Inner += Args[i].getTypeAsString();
197259701Sdim    }
198259701Sdim    return Inner;
199259701Sdim  }
200259701Sdim
201280031Sdim  llvm::Optional<DynTypedMatcher>
202280031Sdim  getTypedMatcher(const MatcherOps &Ops) const override {
203280031Sdim    return Ops.constructVariadicOperator(Op, Args);
204259701Sdim  }
205259701Sdim
206280031Sdim  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
207280031Sdim                       unsigned *Specificity) const override {
208280031Sdim    for (const VariantMatcher &Matcher : Args) {
209280031Sdim      if (!Matcher.isConvertibleTo(Kind, Specificity))
210280031Sdim        return false;
211280031Sdim    }
212280031Sdim    return true;
213280031Sdim  }
214280031Sdim
215259701Sdimprivate:
216280031Sdim  const DynTypedMatcher::VariadicOperator Op;
217259701Sdim  const std::vector<VariantMatcher> Args;
218259701Sdim};
219259701Sdim
220259701SdimVariantMatcher::VariantMatcher() {}
221259701Sdim
222259701SdimVariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
223314564Sdim  return VariantMatcher(std::make_shared<SinglePayload>(Matcher));
224259701Sdim}
225259701Sdim
226259701SdimVariantMatcher
227276479SdimVariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {
228314564Sdim  return VariantMatcher(
229314564Sdim      std::make_shared<PolymorphicPayload>(std::move(Matchers)));
230259701Sdim}
231259701Sdim
232259701SdimVariantMatcher VariantMatcher::VariadicOperatorMatcher(
233280031Sdim    DynTypedMatcher::VariadicOperator Op,
234276479Sdim    std::vector<VariantMatcher> Args) {
235314564Sdim  return VariantMatcher(
236314564Sdim      std::make_shared<VariadicOpPayload>(Op, std::move(Args)));
237259701Sdim}
238259701Sdim
239259701Sdimllvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
240259701Sdim  return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>();
241259701Sdim}
242259701Sdim
243259701Sdimvoid VariantMatcher::reset() { Value.reset(); }
244259701Sdim
245259701Sdimstd::string VariantMatcher::getTypeAsString() const {
246259701Sdim  if (Value) return Value->getTypeAsString();
247259701Sdim  return "<Nothing>";
248259701Sdim}
249259701Sdim
250259701SdimVariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
251259701Sdim  *this = Other;
252259701Sdim}
253259701Sdim
254321369SdimVariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {
255321369Sdim  setBoolean(Boolean);
256321369Sdim}
257321369Sdim
258321369SdimVariantValue::VariantValue(double Double) : Type(VT_Nothing) {
259321369Sdim  setDouble(Double);
260321369Sdim}
261321369Sdim
262259701SdimVariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
263259701Sdim  setUnsigned(Unsigned);
264259701Sdim}
265259701Sdim
266288943SdimVariantValue::VariantValue(StringRef String) : Type(VT_Nothing) {
267259701Sdim  setString(String);
268259701Sdim}
269259701Sdim
270259701SdimVariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) {
271259701Sdim  setMatcher(Matcher);
272259701Sdim}
273259701Sdim
274259701SdimVariantValue::~VariantValue() { reset(); }
275259701Sdim
276259701SdimVariantValue &VariantValue::operator=(const VariantValue &Other) {
277259701Sdim  if (this == &Other) return *this;
278259701Sdim  reset();
279259701Sdim  switch (Other.Type) {
280321369Sdim  case VT_Boolean:
281321369Sdim    setBoolean(Other.getBoolean());
282321369Sdim    break;
283321369Sdim  case VT_Double:
284321369Sdim    setDouble(Other.getDouble());
285321369Sdim    break;
286259701Sdim  case VT_Unsigned:
287259701Sdim    setUnsigned(Other.getUnsigned());
288259701Sdim    break;
289259701Sdim  case VT_String:
290259701Sdim    setString(Other.getString());
291259701Sdim    break;
292259701Sdim  case VT_Matcher:
293259701Sdim    setMatcher(Other.getMatcher());
294259701Sdim    break;
295259701Sdim  case VT_Nothing:
296259701Sdim    Type = VT_Nothing;
297259701Sdim    break;
298259701Sdim  }
299259701Sdim  return *this;
300259701Sdim}
301259701Sdim
302259701Sdimvoid VariantValue::reset() {
303259701Sdim  switch (Type) {
304259701Sdim  case VT_String:
305259701Sdim    delete Value.String;
306259701Sdim    break;
307259701Sdim  case VT_Matcher:
308259701Sdim    delete Value.Matcher;
309259701Sdim    break;
310259701Sdim  // Cases that do nothing.
311321369Sdim  case VT_Boolean:
312321369Sdim  case VT_Double:
313259701Sdim  case VT_Unsigned:
314259701Sdim  case VT_Nothing:
315259701Sdim    break;
316259701Sdim  }
317259701Sdim  Type = VT_Nothing;
318259701Sdim}
319259701Sdim
320321369Sdimbool VariantValue::isBoolean() const {
321321369Sdim  return Type == VT_Boolean;
322321369Sdim}
323321369Sdim
324321369Sdimbool VariantValue::getBoolean() const {
325321369Sdim  assert(isBoolean());
326321369Sdim  return Value.Boolean;
327321369Sdim}
328321369Sdim
329321369Sdimvoid VariantValue::setBoolean(bool NewValue) {
330321369Sdim  reset();
331321369Sdim  Type = VT_Boolean;
332321369Sdim  Value.Boolean = NewValue;
333321369Sdim}
334321369Sdim
335321369Sdimbool VariantValue::isDouble() const {
336321369Sdim  return Type == VT_Double;
337321369Sdim}
338321369Sdim
339321369Sdimdouble VariantValue::getDouble() const {
340321369Sdim  assert(isDouble());
341321369Sdim  return Value.Double;
342321369Sdim}
343321369Sdim
344321369Sdimvoid VariantValue::setDouble(double NewValue) {
345321369Sdim  reset();
346321369Sdim  Type = VT_Double;
347321369Sdim  Value.Double = NewValue;
348321369Sdim}
349321369Sdim
350259701Sdimbool VariantValue::isUnsigned() const {
351259701Sdim  return Type == VT_Unsigned;
352259701Sdim}
353259701Sdim
354259701Sdimunsigned VariantValue::getUnsigned() const {
355259701Sdim  assert(isUnsigned());
356259701Sdim  return Value.Unsigned;
357259701Sdim}
358259701Sdim
359259701Sdimvoid VariantValue::setUnsigned(unsigned NewValue) {
360259701Sdim  reset();
361259701Sdim  Type = VT_Unsigned;
362259701Sdim  Value.Unsigned = NewValue;
363259701Sdim}
364259701Sdim
365259701Sdimbool VariantValue::isString() const {
366259701Sdim  return Type == VT_String;
367259701Sdim}
368259701Sdim
369259701Sdimconst std::string &VariantValue::getString() const {
370259701Sdim  assert(isString());
371259701Sdim  return *Value.String;
372259701Sdim}
373259701Sdim
374288943Sdimvoid VariantValue::setString(StringRef NewValue) {
375259701Sdim  reset();
376259701Sdim  Type = VT_String;
377259701Sdim  Value.String = new std::string(NewValue);
378259701Sdim}
379259701Sdim
380259701Sdimbool VariantValue::isMatcher() const {
381259701Sdim  return Type == VT_Matcher;
382259701Sdim}
383259701Sdim
384259701Sdimconst VariantMatcher &VariantValue::getMatcher() const {
385259701Sdim  assert(isMatcher());
386259701Sdim  return *Value.Matcher;
387259701Sdim}
388259701Sdim
389259701Sdimvoid VariantValue::setMatcher(const VariantMatcher &NewValue) {
390259701Sdim  reset();
391259701Sdim  Type = VT_Matcher;
392259701Sdim  Value.Matcher = new VariantMatcher(NewValue);
393259701Sdim}
394259701Sdim
395280031Sdimbool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
396280031Sdim  switch (Kind.getArgKind()) {
397321369Sdim  case ArgKind::AK_Boolean:
398321369Sdim    if (!isBoolean())
399321369Sdim      return false;
400321369Sdim    *Specificity = 1;
401321369Sdim    return true;
402321369Sdim
403321369Sdim  case ArgKind::AK_Double:
404321369Sdim    if (!isDouble())
405321369Sdim      return false;
406321369Sdim    *Specificity = 1;
407321369Sdim    return true;
408321369Sdim
409280031Sdim  case ArgKind::AK_Unsigned:
410280031Sdim    if (!isUnsigned())
411280031Sdim      return false;
412280031Sdim    *Specificity = 1;
413280031Sdim    return true;
414280031Sdim
415280031Sdim  case ArgKind::AK_String:
416280031Sdim    if (!isString())
417280031Sdim      return false;
418280031Sdim    *Specificity = 1;
419280031Sdim    return true;
420280031Sdim
421280031Sdim  case ArgKind::AK_Matcher:
422280031Sdim    if (!isMatcher())
423280031Sdim      return false;
424280031Sdim    return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity);
425280031Sdim  }
426280031Sdim  llvm_unreachable("Invalid Type");
427280031Sdim}
428280031Sdim
429280031Sdimbool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds,
430280031Sdim                                   unsigned *Specificity) const {
431280031Sdim  unsigned MaxSpecificity = 0;
432280031Sdim  for (const ArgKind& Kind : Kinds) {
433280031Sdim    unsigned ThisSpecificity;
434280031Sdim    if (!isConvertibleTo(Kind, &ThisSpecificity))
435280031Sdim      continue;
436280031Sdim    MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);
437280031Sdim  }
438280031Sdim  if (Specificity && MaxSpecificity > 0) {
439280031Sdim    *Specificity = MaxSpecificity;
440280031Sdim  }
441280031Sdim  return MaxSpecificity > 0;
442280031Sdim}
443280031Sdim
444259701Sdimstd::string VariantValue::getTypeAsString() const {
445259701Sdim  switch (Type) {
446259701Sdim  case VT_String: return "String";
447259701Sdim  case VT_Matcher: return getMatcher().getTypeAsString();
448321369Sdim  case VT_Boolean: return "Boolean";
449321369Sdim  case VT_Double: return "Double";
450259701Sdim  case VT_Unsigned: return "Unsigned";
451259701Sdim  case VT_Nothing: return "Nothing";
452259701Sdim  }
453259701Sdim  llvm_unreachable("Invalid Type");
454259701Sdim}
455259701Sdim
456259701Sdim} // end namespace dynamic
457259701Sdim} // end namespace ast_matchers
458259701Sdim} // end namespace clang
459