1//===--- VariantValue.h - 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/// Supports all the types required for dynamic Matcher construction.
13/// Used by the registry to construct matchers in a generic way.
14///
15//===----------------------------------------------------------------------===//
16
17#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
18#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
19
20#include "clang/ASTMatchers/ASTMatchers.h"
21#include "clang/ASTMatchers/ASTMatchersInternal.h"
22#include "llvm/ADT/IntrusiveRefCntPtr.h"
23#include <memory>
24#include <optional>
25#include <vector>
26
27namespace clang {
28namespace ast_matchers {
29namespace dynamic {
30
31/// Kind identifier.
32///
33/// It supports all types that VariantValue can contain.
34class ArgKind {
35 public:
36 enum Kind {
37 AK_Matcher,
38 AK_Node,
39 AK_Boolean,
40 AK_Double,
41 AK_Unsigned,
42 AK_String
43 };
44 /// Constructor for non-matcher types.
45 ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); }
46
47 /// Constructor for matcher types.
48 static ArgKind MakeMatcherArg(ASTNodeKind MatcherKind) {
49 return ArgKind{AK_Matcher, MatcherKind};
50 }
51
52 static ArgKind MakeNodeArg(ASTNodeKind MatcherKind) {
53 return ArgKind{AK_Node, MatcherKind};
54 }
55
56 Kind getArgKind() const { return K; }
57 ASTNodeKind getMatcherKind() const {
58 assert(K == AK_Matcher);
59 return NodeKind;
60 }
61 ASTNodeKind getNodeKind() const {
62 assert(K == AK_Node);
63 return NodeKind;
64 }
65
66 /// Determines if this type can be converted to \p To.
67 ///
68 /// \param To the requested destination type.
69 ///
70 /// \param Specificity value corresponding to the "specificity" of the
71 /// conversion.
72 bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
73
74 bool operator<(const ArgKind &Other) const {
75 if ((K == AK_Matcher && Other.K == AK_Matcher) ||
76 (K == AK_Node && Other.K == AK_Node))
77 return NodeKind < Other.NodeKind;
78 return K < Other.K;
79 }
80
81 /// String representation of the type.
82 std::string asString() const;
83
84private:
85 ArgKind(Kind K, ASTNodeKind NK) : K(K), NodeKind(NK) {}
86 Kind K;
87 ASTNodeKind NodeKind;
88};
89
90using ast_matchers::internal::DynTypedMatcher;
91
92/// A variant matcher object.
93///
94/// The purpose of this object is to abstract simple and polymorphic matchers
95/// into a single object type.
96/// Polymorphic matchers might be implemented as a list of all the possible
97/// overloads of the matcher. \c VariantMatcher knows how to select the
98/// appropriate overload when needed.
99/// To get a real matcher object out of a \c VariantMatcher you can do:
100/// - getSingleMatcher() which returns a matcher, only if it is not ambiguous
101/// to decide which matcher to return. Eg. it contains only a single
102/// matcher, or a polymorphic one with only one overload.
103/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if
104/// the underlying matcher(s) can unambiguously return a Matcher<T>.
105class VariantMatcher {
106 /// Methods that depend on T from hasTypedMatcher/getTypedMatcher.
107 class MatcherOps {
108 public:
109 MatcherOps(ASTNodeKind NodeKind) : NodeKind(NodeKind) {}
110
111 bool canConstructFrom(const DynTypedMatcher &Matcher,
112 bool &IsExactMatch) const;
113
114 /// Convert \p Matcher the destination type and return it as a new
115 /// DynTypedMatcher.
116 DynTypedMatcher convertMatcher(const DynTypedMatcher &Matcher) const;
117
118 /// Constructs a variadic typed matcher from \p InnerMatchers.
119 /// Will try to convert each inner matcher to the destination type and
120 /// return std::nullopt if it fails to do so.
121 std::optional<DynTypedMatcher>
122 constructVariadicOperator(DynTypedMatcher::VariadicOperator Op,
123 ArrayRef<VariantMatcher> InnerMatchers) const;
124
125 private:
126 ASTNodeKind NodeKind;
127 };
128
129 /// Payload interface to be specialized by each matcher type.
130 ///
131 /// It follows a similar interface as VariantMatcher itself.
132 class Payload {
133 public:
134 virtual ~Payload();
135 virtual std::optional<DynTypedMatcher> getSingleMatcher() const = 0;
136 virtual std::string getTypeAsString() const = 0;
137 virtual std::optional<DynTypedMatcher>
138 getTypedMatcher(const MatcherOps &Ops) const = 0;
139 virtual bool isConvertibleTo(ASTNodeKind Kind,
140 unsigned *Specificity) const = 0;
141 };
142
143public:
144 /// A null matcher.
145 VariantMatcher();
146
147 /// Clones the provided matcher.
148 static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher);
149
150 /// Clones the provided matchers.
151 ///
152 /// They should be the result of a polymorphic matcher.
153 static VariantMatcher
154 PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
155
156 /// Creates a 'variadic' operator matcher.
157 ///
158 /// It will bind to the appropriate type on getTypedMatcher<T>().
159 static VariantMatcher
160 VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op,
161 std::vector<VariantMatcher> Args);
162
163 /// Makes the matcher the "null" matcher.
164 void reset();
165
166 /// Whether the matcher is null.
167 bool isNull() const { return !Value; }
168
169 /// Return a single matcher, if there is no ambiguity.
170 ///
171 /// \returns the matcher, if there is only one matcher. An empty Optional, if
172 /// the underlying matcher is a polymorphic matcher with more than one
173 /// representation.
174 std::optional<DynTypedMatcher> getSingleMatcher() const;
175
176 /// Determines if the contained matcher can be converted to
177 /// \c Matcher<T>.
178 ///
179 /// For the Single case, it returns true if it can be converted to
180 /// \c Matcher<T>.
181 /// For the Polymorphic case, it returns true if one, and only one, of the
182 /// overloads can be converted to \c Matcher<T>. If there are more than one
183 /// that can, the result would be ambiguous and false is returned.
184 template <class T>
185 bool hasTypedMatcher() const {
186 return hasTypedMatcher(ASTNodeKind::getFromNodeKind<T>());
187 }
188
189 bool hasTypedMatcher(ASTNodeKind NK) const {
190 if (!Value) return false;
191 return Value->getTypedMatcher(Ops: MatcherOps(NK)).has_value();
192 }
193
194 /// Determines if the contained matcher can be converted to \p Kind.
195 ///
196 /// \param Kind the requested destination type.
197 ///
198 /// \param Specificity value corresponding to the "specificity" of the
199 /// conversion.
200 bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const {
201 if (Value)
202 return Value->isConvertibleTo(Kind, Specificity);
203 return false;
204 }
205
206 /// Return this matcher as a \c Matcher<T>.
207 ///
208 /// Handles the different types (Single, Polymorphic) accordingly.
209 /// Asserts that \c hasTypedMatcher<T>() is true.
210 template <class T>
211 ast_matchers::internal::Matcher<T> getTypedMatcher() const {
212 assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false");
213 return Value->getTypedMatcher(Ops: MatcherOps(ASTNodeKind::getFromNodeKind<T>()))
214 ->template convertTo<T>();
215 }
216
217 DynTypedMatcher getTypedMatcher(ASTNodeKind NK) const {
218 assert(hasTypedMatcher(NK) && "hasTypedMatcher(NK) == false");
219 return *Value->getTypedMatcher(Ops: MatcherOps(NK));
220 }
221
222 /// String representation of the type of the value.
223 ///
224 /// If the underlying matcher is a polymorphic one, the string will show all
225 /// the types.
226 std::string getTypeAsString() const;
227
228private:
229 explicit VariantMatcher(std::shared_ptr<Payload> Value)
230 : Value(std::move(Value)) {}
231
232
233 class SinglePayload;
234 class PolymorphicPayload;
235 class VariadicOpPayload;
236
237 std::shared_ptr<const Payload> Value;
238};
239
240/// Variant value class.
241///
242/// Basically, a tagged union with value type semantics.
243/// It is used by the registry as the return value and argument type for the
244/// matcher factory methods.
245/// It can be constructed from any of the supported types. It supports
246/// copy/assignment.
247///
248/// Supported types:
249/// - \c bool
250// - \c double
251/// - \c unsigned
252/// - \c llvm::StringRef
253/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
254class VariantValue {
255public:
256 VariantValue() : Type(VT_Nothing) {}
257
258 VariantValue(const VariantValue &Other);
259 ~VariantValue();
260 VariantValue &operator=(const VariantValue &Other);
261
262 /// Specific constructors for each supported type.
263 VariantValue(bool Boolean);
264 VariantValue(double Double);
265 VariantValue(unsigned Unsigned);
266 VariantValue(StringRef String);
267 VariantValue(ASTNodeKind NodeKind);
268 VariantValue(const VariantMatcher &Matchers);
269
270 /// Constructs an \c unsigned value (disambiguation from bool).
271 VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {}
272
273 /// Returns true iff this is not an empty value.
274 explicit operator bool() const { return hasValue(); }
275 bool hasValue() const { return Type != VT_Nothing; }
276
277 /// Boolean value functions.
278 bool isBoolean() const;
279 bool getBoolean() const;
280 void setBoolean(bool Boolean);
281
282 /// Double value functions.
283 bool isDouble() const;
284 double getDouble() const;
285 void setDouble(double Double);
286
287 /// Unsigned value functions.
288 bool isUnsigned() const;
289 unsigned getUnsigned() const;
290 void setUnsigned(unsigned Unsigned);
291
292 /// String value functions.
293 bool isString() const;
294 const std::string &getString() const;
295 void setString(StringRef String);
296
297 bool isNodeKind() const;
298 const ASTNodeKind &getNodeKind() const;
299 void setNodeKind(ASTNodeKind NodeKind);
300
301 /// Matcher value functions.
302 bool isMatcher() const;
303 const VariantMatcher &getMatcher() const;
304 void setMatcher(const VariantMatcher &Matcher);
305
306 /// Determines if the contained value can be converted to \p Kind.
307 ///
308 /// \param Kind the requested destination type.
309 ///
310 /// \param Specificity value corresponding to the "specificity" of the
311 /// conversion.
312 bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
313
314 /// Determines if the contained value can be converted to any kind
315 /// in \p Kinds.
316 ///
317 /// \param Kinds the requested destination types.
318 ///
319 /// \param Specificity value corresponding to the "specificity" of the
320 /// conversion. It is the maximum specificity of all the possible
321 /// conversions.
322 bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
323
324 /// String representation of the type of the value.
325 std::string getTypeAsString() const;
326
327private:
328 void reset();
329
330 /// All supported value types.
331 enum ValueType {
332 VT_Nothing,
333 VT_Boolean,
334 VT_Double,
335 VT_Unsigned,
336 VT_String,
337 VT_Matcher,
338 VT_NodeKind
339 };
340
341 /// All supported value types.
342 union AllValues {
343 unsigned Unsigned;
344 double Double;
345 bool Boolean;
346 std::string *String;
347 VariantMatcher *Matcher;
348 ASTNodeKind *NodeKind;
349 };
350
351 ValueType Type;
352 AllValues Value;
353};
354
355} // end namespace dynamic
356} // end namespace ast_matchers
357} // end namespace clang
358
359#endif // LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
360

source code of clang/include/clang/ASTMatchers/Dynamic/VariantValue.h