1//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief Polymorphic value type.
12///
13//===----------------------------------------------------------------------===//
14
15#include "clang/ASTMatchers/Dynamic/VariantValue.h"
16#include "clang/Basic/LLVM.h"
17#include "llvm/ADT/STLExtras.h"
18
19namespace clang {
20namespace ast_matchers {
21namespace dynamic {
22
23VariantMatcher::MatcherOps::~MatcherOps() {}
24VariantMatcher::Payload::~Payload() {}
25
26class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
27public:
28  SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
29
30  virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
31    return Matcher;
32  }
33
34  virtual std::string getTypeAsString() const {
35    return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
36        .str();
37  }
38
39  virtual void makeTypedMatcher(MatcherOps &Ops) const {
40    bool Ignore;
41    if (Ops.canConstructFrom(Matcher, Ignore))
42      Ops.constructFrom(Matcher);
43  }
44
45private:
46  const DynTypedMatcher Matcher;
47};
48
49class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
50public:
51  PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)
52      : Matchers(std::move(MatchersIn)) {}
53
54  virtual ~PolymorphicPayload() {}
55
56  virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
57    if (Matchers.size() != 1)
58      return llvm::Optional<DynTypedMatcher>();
59    return Matchers[0];
60  }
61
62  virtual std::string getTypeAsString() const {
63    std::string Inner;
64    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
65      if (i != 0)
66        Inner += "|";
67      Inner += Matchers[i].getSupportedKind().asStringRef();
68    }
69    return (Twine("Matcher<") + Inner + ">").str();
70  }
71
72  virtual void makeTypedMatcher(MatcherOps &Ops) const {
73    bool FoundIsExact = false;
74    const DynTypedMatcher *Found = nullptr;
75    int NumFound = 0;
76    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
77      bool IsExactMatch;
78      if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) {
79        if (Found) {
80          if (FoundIsExact) {
81            assert(!IsExactMatch && "We should not have two exact matches.");
82            continue;
83          }
84        }
85        Found = &Matchers[i];
86        FoundIsExact = IsExactMatch;
87        ++NumFound;
88      }
89    }
90    // We only succeed if we found exactly one, or if we found an exact match.
91    if (Found && (FoundIsExact || NumFound == 1))
92      Ops.constructFrom(*Found);
93  }
94
95  const std::vector<DynTypedMatcher> Matchers;
96};
97
98class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
99public:
100  VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func,
101                    std::vector<VariantMatcher> Args)
102      : Func(Func), Args(std::move(Args)) {}
103
104  virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
105    return llvm::Optional<DynTypedMatcher>();
106  }
107
108  virtual std::string getTypeAsString() const {
109    std::string Inner;
110    for (size_t i = 0, e = Args.size(); i != e; ++i) {
111      if (i != 0)
112        Inner += "&";
113      Inner += Args[i].getTypeAsString();
114    }
115    return Inner;
116  }
117
118  virtual void makeTypedMatcher(MatcherOps &Ops) const {
119    Ops.constructVariadicOperator(Func, Args);
120  }
121
122private:
123  const ast_matchers::internal::VariadicOperatorFunction Func;
124  const std::vector<VariantMatcher> Args;
125};
126
127VariantMatcher::VariantMatcher() {}
128
129VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
130  return VariantMatcher(new SinglePayload(Matcher));
131}
132
133VariantMatcher
134VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {
135  return VariantMatcher(new PolymorphicPayload(std::move(Matchers)));
136}
137
138VariantMatcher VariantMatcher::VariadicOperatorMatcher(
139    ast_matchers::internal::VariadicOperatorFunction Func,
140    std::vector<VariantMatcher> Args) {
141  return VariantMatcher(new VariadicOpPayload(Func, std::move(Args)));
142}
143
144llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
145  return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>();
146}
147
148void VariantMatcher::reset() { Value.reset(); }
149
150std::string VariantMatcher::getTypeAsString() const {
151  if (Value) return Value->getTypeAsString();
152  return "<Nothing>";
153}
154
155VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
156  *this = Other;
157}
158
159VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
160  setUnsigned(Unsigned);
161}
162
163VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) {
164  setString(String);
165}
166
167VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) {
168  setMatcher(Matcher);
169}
170
171VariantValue::~VariantValue() { reset(); }
172
173VariantValue &VariantValue::operator=(const VariantValue &Other) {
174  if (this == &Other) return *this;
175  reset();
176  switch (Other.Type) {
177  case VT_Unsigned:
178    setUnsigned(Other.getUnsigned());
179    break;
180  case VT_String:
181    setString(Other.getString());
182    break;
183  case VT_Matcher:
184    setMatcher(Other.getMatcher());
185    break;
186  case VT_Nothing:
187    Type = VT_Nothing;
188    break;
189  }
190  return *this;
191}
192
193void VariantValue::reset() {
194  switch (Type) {
195  case VT_String:
196    delete Value.String;
197    break;
198  case VT_Matcher:
199    delete Value.Matcher;
200    break;
201  // Cases that do nothing.
202  case VT_Unsigned:
203  case VT_Nothing:
204    break;
205  }
206  Type = VT_Nothing;
207}
208
209bool VariantValue::isUnsigned() const {
210  return Type == VT_Unsigned;
211}
212
213unsigned VariantValue::getUnsigned() const {
214  assert(isUnsigned());
215  return Value.Unsigned;
216}
217
218void VariantValue::setUnsigned(unsigned NewValue) {
219  reset();
220  Type = VT_Unsigned;
221  Value.Unsigned = NewValue;
222}
223
224bool VariantValue::isString() const {
225  return Type == VT_String;
226}
227
228const std::string &VariantValue::getString() const {
229  assert(isString());
230  return *Value.String;
231}
232
233void VariantValue::setString(const std::string &NewValue) {
234  reset();
235  Type = VT_String;
236  Value.String = new std::string(NewValue);
237}
238
239bool VariantValue::isMatcher() const {
240  return Type == VT_Matcher;
241}
242
243const VariantMatcher &VariantValue::getMatcher() const {
244  assert(isMatcher());
245  return *Value.Matcher;
246}
247
248void VariantValue::setMatcher(const VariantMatcher &NewValue) {
249  reset();
250  Type = VT_Matcher;
251  Value.Matcher = new VariantMatcher(NewValue);
252}
253
254std::string VariantValue::getTypeAsString() const {
255  switch (Type) {
256  case VT_String: return "String";
257  case VT_Matcher: return getMatcher().getTypeAsString();
258  case VT_Unsigned: return "Unsigned";
259  case VT_Nothing: return "Nothing";
260  }
261  llvm_unreachable("Invalid Type");
262}
263
264} // end namespace dynamic
265} // end namespace ast_matchers
266} // end namespace clang
267