1259701Sdim//===--- VariantValue.h - Polymorphic value type -*- C++ -*-===/
2353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3353358Sdim// See https://llvm.org/LICENSE.txt for license information.
4353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5259701Sdim//
6259701Sdim//===----------------------------------------------------------------------===//
7259701Sdim///
8259701Sdim/// \file
9341825Sdim/// Polymorphic value type.
10259701Sdim///
11259701Sdim/// Supports all the types required for dynamic Matcher construction.
12259701Sdim///  Used by the registry to construct matchers in a generic way.
13259701Sdim///
14259701Sdim//===----------------------------------------------------------------------===//
15259701Sdim
16280031Sdim#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
17280031Sdim#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
18259701Sdim
19259701Sdim#include "clang/ASTMatchers/ASTMatchers.h"
20259701Sdim#include "clang/ASTMatchers/ASTMatchersInternal.h"
21259701Sdim#include "llvm/ADT/IntrusiveRefCntPtr.h"
22259701Sdim#include "llvm/ADT/Optional.h"
23276479Sdim#include <memory>
24276479Sdim#include <vector>
25259701Sdim
26259701Sdimnamespace clang {
27259701Sdimnamespace ast_matchers {
28259701Sdimnamespace dynamic {
29259701Sdim
30341825Sdim/// Kind identifier.
31280031Sdim///
32280031Sdim/// It supports all types that VariantValue can contain.
33280031Sdimclass ArgKind {
34280031Sdim public:
35280031Sdim  enum Kind {
36280031Sdim    AK_Matcher,
37321369Sdim    AK_Boolean,
38321369Sdim    AK_Double,
39280031Sdim    AK_Unsigned,
40280031Sdim    AK_String
41280031Sdim  };
42341825Sdim  /// Constructor for non-matcher types.
43280031Sdim  ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); }
44280031Sdim
45341825Sdim  /// Constructor for matcher types.
46280031Sdim  ArgKind(ast_type_traits::ASTNodeKind MatcherKind)
47280031Sdim      : K(AK_Matcher), MatcherKind(MatcherKind) {}
48280031Sdim
49280031Sdim  Kind getArgKind() const { return K; }
50280031Sdim  ast_type_traits::ASTNodeKind getMatcherKind() const {
51280031Sdim    assert(K == AK_Matcher);
52280031Sdim    return MatcherKind;
53280031Sdim  }
54280031Sdim
55341825Sdim  /// Determines if this type can be converted to \p To.
56280031Sdim  ///
57280031Sdim  /// \param To the requested destination type.
58280031Sdim  ///
59280031Sdim  /// \param Specificity value corresponding to the "specificity" of the
60321369Sdim  ///   conversion.
61280031Sdim  bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
62280031Sdim
63280031Sdim  bool operator<(const ArgKind &Other) const {
64280031Sdim    if (K == AK_Matcher && Other.K == AK_Matcher)
65280031Sdim      return MatcherKind < Other.MatcherKind;
66280031Sdim    return K < Other.K;
67280031Sdim  }
68280031Sdim
69341825Sdim  /// String representation of the type.
70280031Sdim  std::string asString() const;
71280031Sdim
72280031Sdimprivate:
73280031Sdim  Kind K;
74280031Sdim  ast_type_traits::ASTNodeKind MatcherKind;
75280031Sdim};
76280031Sdim
77259701Sdimusing ast_matchers::internal::DynTypedMatcher;
78259701Sdim
79341825Sdim/// A variant matcher object.
80259701Sdim///
81259701Sdim/// The purpose of this object is to abstract simple and polymorphic matchers
82259701Sdim/// into a single object type.
83259701Sdim/// Polymorphic matchers might be implemented as a list of all the possible
84259701Sdim/// overloads of the matcher. \c VariantMatcher knows how to select the
85259701Sdim/// appropriate overload when needed.
86259701Sdim/// To get a real matcher object out of a \c VariantMatcher you can do:
87259701Sdim///  - getSingleMatcher() which returns a matcher, only if it is not ambiguous
88259701Sdim///    to decide which matcher to return. Eg. it contains only a single
89259701Sdim///    matcher, or a polymorphic one with only one overload.
90259701Sdim///  - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if
91259701Sdim///    the underlying matcher(s) can unambiguously return a Matcher<T>.
92259701Sdimclass VariantMatcher {
93341825Sdim  /// Methods that depend on T from hasTypedMatcher/getTypedMatcher.
94259701Sdim  class MatcherOps {
95259701Sdim  public:
96280031Sdim    MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {}
97280031Sdim
98280031Sdim    bool canConstructFrom(const DynTypedMatcher &Matcher,
99280031Sdim                          bool &IsExactMatch) const;
100280031Sdim
101341825Sdim    /// Convert \p Matcher the destination type and return it as a new
102280031Sdim    /// DynTypedMatcher.
103280031Sdim    virtual DynTypedMatcher
104280031Sdim    convertMatcher(const DynTypedMatcher &Matcher) const = 0;
105280031Sdim
106341825Sdim    /// Constructs a variadic typed matcher from \p InnerMatchers.
107280031Sdim    /// Will try to convert each inner matcher to the destination type and
108280031Sdim    /// return llvm::None if it fails to do so.
109280031Sdim    llvm::Optional<DynTypedMatcher>
110280031Sdim    constructVariadicOperator(DynTypedMatcher::VariadicOperator Op,
111280031Sdim                              ArrayRef<VariantMatcher> InnerMatchers) const;
112280031Sdim
113280031Sdim  protected:
114288943Sdim    ~MatcherOps() = default;
115280031Sdim
116280031Sdim  private:
117280031Sdim    ast_type_traits::ASTNodeKind NodeKind;
118259701Sdim  };
119259701Sdim
120341825Sdim  /// Payload interface to be specialized by each matcher type.
121259701Sdim  ///
122259701Sdim  /// It follows a similar interface as VariantMatcher itself.
123314564Sdim  class Payload {
124259701Sdim  public:
125314564Sdim    virtual ~Payload();
126259701Sdim    virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
127259701Sdim    virtual std::string getTypeAsString() const = 0;
128280031Sdim    virtual llvm::Optional<DynTypedMatcher>
129280031Sdim    getTypedMatcher(const MatcherOps &Ops) const = 0;
130280031Sdim    virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
131280031Sdim                                 unsigned *Specificity) const = 0;
132259701Sdim  };
133259701Sdim
134259701Sdimpublic:
135341825Sdim  /// A null matcher.
136259701Sdim  VariantMatcher();
137259701Sdim
138341825Sdim  /// Clones the provided matcher.
139259701Sdim  static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher);
140259701Sdim
141341825Sdim  /// Clones the provided matchers.
142259701Sdim  ///
143259701Sdim  /// They should be the result of a polymorphic matcher.
144276479Sdim  static VariantMatcher
145276479Sdim  PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
146259701Sdim
147341825Sdim  /// Creates a 'variadic' operator matcher.
148259701Sdim  ///
149259701Sdim  /// It will bind to the appropriate type on getTypedMatcher<T>().
150280031Sdim  static VariantMatcher
151280031Sdim  VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op,
152280031Sdim                          std::vector<VariantMatcher> Args);
153259701Sdim
154341825Sdim  /// Makes the matcher the "null" matcher.
155259701Sdim  void reset();
156259701Sdim
157341825Sdim  /// Whether the matcher is null.
158259701Sdim  bool isNull() const { return !Value; }
159259701Sdim
160341825Sdim  /// Return a single matcher, if there is no ambiguity.
161259701Sdim  ///
162259701Sdim  /// \returns the matcher, if there is only one matcher. An empty Optional, if
163259701Sdim  /// the underlying matcher is a polymorphic matcher with more than one
164259701Sdim  /// representation.
165259701Sdim  llvm::Optional<DynTypedMatcher> getSingleMatcher() const;
166259701Sdim
167341825Sdim  /// Determines if the contained matcher can be converted to
168259701Sdim  ///   \c Matcher<T>.
169259701Sdim  ///
170259701Sdim  /// For the Single case, it returns true if it can be converted to
171259701Sdim  /// \c Matcher<T>.
172259701Sdim  /// For the Polymorphic case, it returns true if one, and only one, of the
173259701Sdim  /// overloads can be converted to \c Matcher<T>. If there are more than one
174259701Sdim  /// that can, the result would be ambiguous and false is returned.
175259701Sdim  template <class T>
176259701Sdim  bool hasTypedMatcher() const {
177280031Sdim    if (!Value) return false;
178280031Sdim    return Value->getTypedMatcher(TypedMatcherOps<T>()).hasValue();
179259701Sdim  }
180259701Sdim
181341825Sdim  /// Determines if the contained matcher can be converted to \p Kind.
182280031Sdim  ///
183280031Sdim  /// \param Kind the requested destination type.
184280031Sdim  ///
185280031Sdim  /// \param Specificity value corresponding to the "specificity" of the
186321369Sdim  ///   conversion.
187280031Sdim  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
188280031Sdim                       unsigned *Specificity) const {
189280031Sdim    if (Value)
190280031Sdim      return Value->isConvertibleTo(Kind, Specificity);
191280031Sdim    return false;
192280031Sdim  }
193280031Sdim
194341825Sdim  /// Return this matcher as a \c Matcher<T>.
195259701Sdim  ///
196259701Sdim  /// Handles the different types (Single, Polymorphic) accordingly.
197259701Sdim  /// Asserts that \c hasTypedMatcher<T>() is true.
198259701Sdim  template <class T>
199259701Sdim  ast_matchers::internal::Matcher<T> getTypedMatcher() const {
200280031Sdim    assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false");
201280031Sdim    return Value->getTypedMatcher(TypedMatcherOps<T>())
202280031Sdim        ->template convertTo<T>();
203259701Sdim  }
204259701Sdim
205341825Sdim  /// String representation of the type of the value.
206259701Sdim  ///
207259701Sdim  /// If the underlying matcher is a polymorphic one, the string will show all
208259701Sdim  /// the types.
209259701Sdim  std::string getTypeAsString() const;
210259701Sdim
211259701Sdimprivate:
212314564Sdim  explicit VariantMatcher(std::shared_ptr<Payload> Value)
213314564Sdim      : Value(std::move(Value)) {}
214259701Sdim
215280031Sdim  template <typename T> struct TypedMatcherOps;
216280031Sdim
217259701Sdim  class SinglePayload;
218259701Sdim  class PolymorphicPayload;
219259701Sdim  class VariadicOpPayload;
220259701Sdim
221314564Sdim  std::shared_ptr<const Payload> Value;
222280031Sdim};
223259701Sdim
224280031Sdimtemplate <typename T>
225280031Sdimstruct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
226280031Sdim  TypedMatcherOps()
227280031Sdim      : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()) {}
228280031Sdim  typedef ast_matchers::internal::Matcher<T> MatcherT;
229259701Sdim
230280031Sdim  DynTypedMatcher
231280031Sdim  convertMatcher(const DynTypedMatcher &Matcher) const override {
232280031Sdim    return DynTypedMatcher(Matcher.convertTo<T>());
233280031Sdim  }
234259701Sdim};
235259701Sdim
236341825Sdim/// Variant value class.
237259701Sdim///
238259701Sdim/// Basically, a tagged union with value type semantics.
239259701Sdim/// It is used by the registry as the return value and argument type for the
240259701Sdim/// matcher factory methods.
241259701Sdim/// It can be constructed from any of the supported types. It supports
242259701Sdim/// copy/assignment.
243259701Sdim///
244259701Sdim/// Supported types:
245321369Sdim///  - \c bool
246321369Sdim//   - \c double
247259701Sdim///  - \c unsigned
248288943Sdim///  - \c llvm::StringRef
249259701Sdim///  - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
250259701Sdimclass VariantValue {
251259701Sdimpublic:
252259701Sdim  VariantValue() : Type(VT_Nothing) {}
253259701Sdim
254259701Sdim  VariantValue(const VariantValue &Other);
255259701Sdim  ~VariantValue();
256259701Sdim  VariantValue &operator=(const VariantValue &Other);
257259701Sdim
258341825Sdim  /// Specific constructors for each supported type.
259321369Sdim  VariantValue(bool Boolean);
260321369Sdim  VariantValue(double Double);
261259701Sdim  VariantValue(unsigned Unsigned);
262288943Sdim  VariantValue(StringRef String);
263259701Sdim  VariantValue(const VariantMatcher &Matchers);
264259701Sdim
265341825Sdim  /// Constructs an \c unsigned value (disambiguation from bool).
266321369Sdim  VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {}
267321369Sdim
268341825Sdim  /// Returns true iff this is not an empty value.
269288943Sdim  explicit operator bool() const { return hasValue(); }
270276479Sdim  bool hasValue() const { return Type != VT_Nothing; }
271276479Sdim
272341825Sdim  /// Boolean value functions.
273321369Sdim  bool isBoolean() const;
274321369Sdim  bool getBoolean() const;
275321369Sdim  void setBoolean(bool Boolean);
276321369Sdim
277341825Sdim  /// Double value functions.
278321369Sdim  bool isDouble() const;
279321369Sdim  double getDouble() const;
280321369Sdim  void setDouble(double Double);
281321369Sdim
282341825Sdim  /// Unsigned value functions.
283259701Sdim  bool isUnsigned() const;
284259701Sdim  unsigned getUnsigned() const;
285259701Sdim  void setUnsigned(unsigned Unsigned);
286259701Sdim
287341825Sdim  /// String value functions.
288259701Sdim  bool isString() const;
289259701Sdim  const std::string &getString() const;
290288943Sdim  void setString(StringRef String);
291259701Sdim
292341825Sdim  /// Matcher value functions.
293259701Sdim  bool isMatcher() const;
294259701Sdim  const VariantMatcher &getMatcher() const;
295259701Sdim  void setMatcher(const VariantMatcher &Matcher);
296259701Sdim
297341825Sdim  /// Determines if the contained value can be converted to \p Kind.
298280031Sdim  ///
299280031Sdim  /// \param Kind the requested destination type.
300280031Sdim  ///
301280031Sdim  /// \param Specificity value corresponding to the "specificity" of the
302321369Sdim  ///   conversion.
303280031Sdim  bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
304280031Sdim
305341825Sdim  /// Determines if the contained value can be converted to any kind
306280031Sdim  /// in \p Kinds.
307280031Sdim  ///
308280031Sdim  /// \param Kinds the requested destination types.
309280031Sdim  ///
310280031Sdim  /// \param Specificity value corresponding to the "specificity" of the
311321369Sdim  ///   conversion. It is the maximum specificity of all the possible
312280031Sdim  ///   conversions.
313280031Sdim  bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
314280031Sdim
315341825Sdim  /// String representation of the type of the value.
316259701Sdim  std::string getTypeAsString() const;
317259701Sdim
318259701Sdimprivate:
319259701Sdim  void reset();
320259701Sdim
321341825Sdim  /// All supported value types.
322259701Sdim  enum ValueType {
323259701Sdim    VT_Nothing,
324321369Sdim    VT_Boolean,
325321369Sdim    VT_Double,
326259701Sdim    VT_Unsigned,
327259701Sdim    VT_String,
328259701Sdim    VT_Matcher
329259701Sdim  };
330259701Sdim
331341825Sdim  /// All supported value types.
332259701Sdim  union AllValues {
333259701Sdim    unsigned Unsigned;
334321369Sdim    double Double;
335321369Sdim    bool Boolean;
336259701Sdim    std::string *String;
337259701Sdim    VariantMatcher *Matcher;
338259701Sdim  };
339259701Sdim
340259701Sdim  ValueType Type;
341259701Sdim  AllValues Value;
342259701Sdim};
343259701Sdim
344259701Sdim} // end namespace dynamic
345259701Sdim} // end namespace ast_matchers
346259701Sdim} // end namespace clang
347259701Sdim
348259701Sdim#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H
349