1 | //===--- ASTTypeTraits.h ----------------------------------------*- 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 | // Provides a dynamic type identifier and a dynamically typed node container |
10 | // that can be used to store an AST base node at runtime in the same storage in |
11 | // a type safe way. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #ifndef LLVM_CLANG_AST_ASTTYPETRAITS_H |
16 | #define LLVM_CLANG_AST_ASTTYPETRAITS_H |
17 | |
18 | #include "clang/AST/ASTFwd.h" |
19 | #include "clang/AST/DeclCXX.h" |
20 | #include "clang/AST/LambdaCapture.h" |
21 | #include "clang/AST/NestedNameSpecifier.h" |
22 | #include "clang/AST/TemplateBase.h" |
23 | #include "clang/AST/TypeLoc.h" |
24 | #include "clang/Basic/LLVM.h" |
25 | #include "llvm/ADT/DenseMapInfo.h" |
26 | #include "llvm/Support/AlignOf.h" |
27 | |
28 | namespace llvm { |
29 | class raw_ostream; |
30 | } // namespace llvm |
31 | |
32 | namespace clang { |
33 | |
34 | struct PrintingPolicy; |
35 | |
36 | /// Defines how we descend a level in the AST when we pass |
37 | /// through expressions. |
38 | enum TraversalKind { |
39 | /// Will traverse all child nodes. |
40 | TK_AsIs, |
41 | |
42 | /// Ignore AST nodes not written in the source |
43 | TK_IgnoreUnlessSpelledInSource |
44 | }; |
45 | |
46 | /// Kind identifier. |
47 | /// |
48 | /// It can be constructed from any node kind and allows for runtime type |
49 | /// hierarchy checks. |
50 | /// Use getFromNodeKind<T>() to construct them. |
51 | class ASTNodeKind { |
52 | public: |
53 | /// Empty identifier. It matches nothing. |
54 | constexpr ASTNodeKind() : KindId(NKI_None) {} |
55 | |
56 | /// Construct an identifier for T. |
57 | template <class T> static constexpr ASTNodeKind getFromNodeKind() { |
58 | return ASTNodeKind(KindToKindId<T>::Id); |
59 | } |
60 | |
61 | /// \{ |
62 | /// Construct an identifier for the dynamic type of the node |
63 | static ASTNodeKind getFromNode(const Decl &D); |
64 | static ASTNodeKind getFromNode(const Stmt &S); |
65 | static ASTNodeKind getFromNode(const Type &T); |
66 | static ASTNodeKind getFromNode(const TypeLoc &T); |
67 | static ASTNodeKind getFromNode(const LambdaCapture &L); |
68 | static ASTNodeKind getFromNode(const OMPClause &C); |
69 | static ASTNodeKind getFromNode(const Attr &A); |
70 | /// \} |
71 | |
72 | /// Returns \c true if \c this and \c Other represent the same kind. |
73 | constexpr bool isSame(ASTNodeKind Other) const { |
74 | return KindId != NKI_None && KindId == Other.KindId; |
75 | } |
76 | |
77 | /// Returns \c true only for the default \c ASTNodeKind() |
78 | constexpr bool isNone() const { return KindId == NKI_None; } |
79 | |
80 | /// Returns \c true if \c this is a base kind of (or same as) \c Other. |
81 | bool isBaseOf(ASTNodeKind Other) const; |
82 | |
83 | /// Returns \c true if \c this is a base kind of (or same as) \c Other. |
84 | /// \param Distance If non-null, used to return the distance between \c this |
85 | /// and \c Other in the class hierarchy. |
86 | bool isBaseOf(ASTNodeKind Other, unsigned *Distance) const; |
87 | |
88 | /// String representation of the kind. |
89 | StringRef asStringRef() const; |
90 | |
91 | /// Strict weak ordering for ASTNodeKind. |
92 | constexpr bool operator<(const ASTNodeKind &Other) const { |
93 | return KindId < Other.KindId; |
94 | } |
95 | |
96 | /// Return the most derived type between \p Kind1 and \p Kind2. |
97 | /// |
98 | /// Return ASTNodeKind() if they are not related. |
99 | static ASTNodeKind getMostDerivedType(ASTNodeKind Kind1, ASTNodeKind Kind2); |
100 | |
101 | /// Return the most derived common ancestor between Kind1 and Kind2. |
102 | /// |
103 | /// Return ASTNodeKind() if they are not related. |
104 | static ASTNodeKind getMostDerivedCommonAncestor(ASTNodeKind Kind1, |
105 | ASTNodeKind Kind2); |
106 | |
107 | ASTNodeKind getCladeKind() const; |
108 | |
109 | /// Hooks for using ASTNodeKind as a key in a DenseMap. |
110 | struct DenseMapInfo { |
111 | // ASTNodeKind() is a good empty key because it is represented as a 0. |
112 | static inline ASTNodeKind getEmptyKey() { return ASTNodeKind(); } |
113 | // NKI_NumberOfKinds is not a valid value, so it is good for a |
114 | // tombstone key. |
115 | static inline ASTNodeKind getTombstoneKey() { |
116 | return ASTNodeKind(NKI_NumberOfKinds); |
117 | } |
118 | static unsigned getHashValue(const ASTNodeKind &Val) { return Val.KindId; } |
119 | static bool isEqual(const ASTNodeKind &LHS, const ASTNodeKind &RHS) { |
120 | return LHS.KindId == RHS.KindId; |
121 | } |
122 | }; |
123 | |
124 | /// Check if the given ASTNodeKind identifies a type that offers pointer |
125 | /// identity. This is useful for the fast path in DynTypedNode. |
126 | constexpr bool hasPointerIdentity() const { |
127 | return KindId > NKI_LastKindWithoutPointerIdentity; |
128 | } |
129 | |
130 | private: |
131 | /// Kind ids. |
132 | /// |
133 | /// Includes all possible base and derived kinds. |
134 | enum NodeKindId { |
135 | NKI_None, |
136 | NKI_TemplateArgument, |
137 | NKI_TemplateArgumentLoc, |
138 | NKI_LambdaCapture, |
139 | NKI_TemplateName, |
140 | NKI_NestedNameSpecifierLoc, |
141 | NKI_QualType, |
142 | #define TYPELOC(CLASS, PARENT) NKI_##CLASS##TypeLoc, |
143 | #include "clang/AST/TypeLocNodes.def" |
144 | NKI_TypeLoc, |
145 | NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc, |
146 | NKI_CXXBaseSpecifier, |
147 | NKI_CXXCtorInitializer, |
148 | NKI_NestedNameSpecifier, |
149 | NKI_Decl, |
150 | #define DECL(DERIVED, BASE) NKI_##DERIVED##Decl, |
151 | #include "clang/AST/DeclNodes.inc" |
152 | NKI_Stmt, |
153 | #define STMT(DERIVED, BASE) NKI_##DERIVED, |
154 | #include "clang/AST/StmtNodes.inc" |
155 | NKI_Type, |
156 | #define TYPE(DERIVED, BASE) NKI_##DERIVED##Type, |
157 | #include "clang/AST/TypeNodes.inc" |
158 | NKI_OMPClause, |
159 | #define GEN_CLANG_CLAUSE_CLASS |
160 | #define CLAUSE_CLASS(Enum, Str, Class) NKI_##Class, |
161 | #include "llvm/Frontend/OpenMP/OMP.inc" |
162 | NKI_Attr, |
163 | #define ATTR(A) NKI_##A##Attr, |
164 | #include "clang/Basic/AttrList.inc" |
165 | NKI_ObjCProtocolLoc, |
166 | NKI_ConceptReference, |
167 | NKI_NumberOfKinds |
168 | }; |
169 | |
170 | /// Use getFromNodeKind<T>() to construct the kind. |
171 | constexpr ASTNodeKind(NodeKindId KindId) : KindId(KindId) {} |
172 | |
173 | /// Returns \c true if \c Base is a base kind of (or same as) \c |
174 | /// Derived. |
175 | static bool isBaseOf(NodeKindId Base, NodeKindId Derived); |
176 | |
177 | /// Returns \c true if \c Base is a base kind of (or same as) \c |
178 | /// Derived. |
179 | /// \param Distance If non-null, used to return the distance between \c Base |
180 | /// and \c Derived in the class hierarchy. |
181 | static bool isBaseOf(NodeKindId Base, NodeKindId Derived, unsigned *Distance); |
182 | |
183 | /// Helper meta-function to convert a kind T to its enum value. |
184 | /// |
185 | /// This struct is specialized below for all known kinds. |
186 | template <class T> struct KindToKindId { |
187 | static const NodeKindId Id = NKI_None; |
188 | }; |
189 | template <class T> |
190 | struct KindToKindId<const T> : KindToKindId<T> {}; |
191 | |
192 | /// Per kind info. |
193 | struct KindInfo { |
194 | /// The id of the parent kind, or None if it has no parent. |
195 | NodeKindId ParentId; |
196 | /// Name of the kind. |
197 | const char *Name; |
198 | }; |
199 | static const KindInfo AllKindInfo[NKI_NumberOfKinds]; |
200 | |
201 | NodeKindId KindId; |
202 | }; |
203 | |
204 | #define KIND_TO_KIND_ID(Class) \ |
205 | template <> struct ASTNodeKind::KindToKindId<Class> { \ |
206 | static const NodeKindId Id = NKI_##Class; \ |
207 | }; |
208 | KIND_TO_KIND_ID(CXXCtorInitializer) |
209 | KIND_TO_KIND_ID(TemplateArgument) |
210 | KIND_TO_KIND_ID(TemplateArgumentLoc) |
211 | KIND_TO_KIND_ID(LambdaCapture) |
212 | KIND_TO_KIND_ID(TemplateName) |
213 | KIND_TO_KIND_ID(NestedNameSpecifier) |
214 | KIND_TO_KIND_ID(NestedNameSpecifierLoc) |
215 | KIND_TO_KIND_ID(QualType) |
216 | #define TYPELOC(CLASS, PARENT) KIND_TO_KIND_ID(CLASS##TypeLoc) |
217 | #include "clang/AST/TypeLocNodes.def" |
218 | KIND_TO_KIND_ID(TypeLoc) |
219 | KIND_TO_KIND_ID(Decl) |
220 | KIND_TO_KIND_ID(Stmt) |
221 | KIND_TO_KIND_ID(Type) |
222 | KIND_TO_KIND_ID(OMPClause) |
223 | KIND_TO_KIND_ID(Attr) |
224 | KIND_TO_KIND_ID(ObjCProtocolLoc) |
225 | KIND_TO_KIND_ID(CXXBaseSpecifier) |
226 | KIND_TO_KIND_ID(ConceptReference) |
227 | #define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl) |
228 | #include "clang/AST/DeclNodes.inc" |
229 | #define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED) |
230 | #include "clang/AST/StmtNodes.inc" |
231 | #define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type) |
232 | #include "clang/AST/TypeNodes.inc" |
233 | #define GEN_CLANG_CLAUSE_CLASS |
234 | #define CLAUSE_CLASS(Enum, Str, Class) KIND_TO_KIND_ID(Class) |
235 | #include "llvm/Frontend/OpenMP/OMP.inc" |
236 | #define ATTR(A) KIND_TO_KIND_ID(A##Attr) |
237 | #include "clang/Basic/AttrList.inc" |
238 | #undef KIND_TO_KIND_ID |
239 | |
240 | inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) { |
241 | OS << K.asStringRef(); |
242 | return OS; |
243 | } |
244 | |
245 | /// A dynamically typed AST node container. |
246 | /// |
247 | /// Stores an AST node in a type safe way. This allows writing code that |
248 | /// works with different kinds of AST nodes, despite the fact that they don't |
249 | /// have a common base class. |
250 | /// |
251 | /// Use \c create(Node) to create a \c DynTypedNode from an AST node, |
252 | /// and \c get<T>() to retrieve the node as type T if the types match. |
253 | /// |
254 | /// See \c ASTNodeKind for which node base types are currently supported; |
255 | /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of |
256 | /// the supported base types. |
257 | class DynTypedNode { |
258 | public: |
259 | /// Creates a \c DynTypedNode from \c Node. |
260 | template <typename T> |
261 | static DynTypedNode create(const T &Node) { |
262 | return BaseConverter<T>::create(Node); |
263 | } |
264 | |
265 | /// Retrieve the stored node as type \c T. |
266 | /// |
267 | /// Returns NULL if the stored node does not have a type that is |
268 | /// convertible to \c T. |
269 | /// |
270 | /// For types that have identity via their pointer in the AST |
271 | /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned |
272 | /// pointer points to the referenced AST node. |
273 | /// For other types (like \c QualType) the value is stored directly |
274 | /// in the \c DynTypedNode, and the returned pointer points at |
275 | /// the storage inside DynTypedNode. For those nodes, do not |
276 | /// use the pointer outside the scope of the DynTypedNode. |
277 | template <typename T> const T *get() const { |
278 | return BaseConverter<T>::get(NodeKind, &Storage); |
279 | } |
280 | |
281 | /// Retrieve the stored node as type \c T. |
282 | /// |
283 | /// Similar to \c get(), but asserts that the type is what we are expecting. |
284 | template <typename T> |
285 | const T &getUnchecked() const { |
286 | return BaseConverter<T>::getUnchecked(NodeKind, &Storage); |
287 | } |
288 | |
289 | ASTNodeKind getNodeKind() const { return NodeKind; } |
290 | |
291 | /// Returns a pointer that identifies the stored AST node. |
292 | /// |
293 | /// Note that this is not supported by all AST nodes. For AST nodes |
294 | /// that don't have a pointer-defined identity inside the AST, this |
295 | /// method returns NULL. |
296 | const void *getMemoizationData() const { |
297 | return NodeKind.hasPointerIdentity() |
298 | ? *reinterpret_cast<void *const *>(&Storage) |
299 | : nullptr; |
300 | } |
301 | |
302 | /// Prints the node to the given output stream. |
303 | void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const; |
304 | |
305 | /// Dumps the node to the given output stream. |
306 | void dump(llvm::raw_ostream &OS, const ASTContext &Context) const; |
307 | |
308 | /// For nodes which represent textual entities in the source code, |
309 | /// return their SourceRange. For all other nodes, return SourceRange(). |
310 | SourceRange getSourceRange() const; |
311 | |
312 | /// @{ |
313 | /// Imposes an order on \c DynTypedNode. |
314 | /// |
315 | /// Supports comparison of nodes that support memoization. |
316 | /// FIXME: Implement comparison for other node types (currently |
317 | /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data). |
318 | bool operator<(const DynTypedNode &Other) const { |
319 | if (!NodeKind.isSame(Other: Other.NodeKind)) |
320 | return NodeKind < Other.NodeKind; |
321 | |
322 | if (ASTNodeKind::getFromNodeKind<QualType>().isSame(Other: NodeKind)) |
323 | return getUnchecked<QualType>().getAsOpaquePtr() < |
324 | Other.getUnchecked<QualType>().getAsOpaquePtr(); |
325 | |
326 | if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(Other: NodeKind)) { |
327 | auto TLA = getUnchecked<TypeLoc>(); |
328 | auto TLB = Other.getUnchecked<TypeLoc>(); |
329 | return std::make_pair(TLA.getType().getAsOpaquePtr(), |
330 | TLA.getOpaqueData()) < |
331 | std::make_pair(TLB.getType().getAsOpaquePtr(), |
332 | TLB.getOpaqueData()); |
333 | } |
334 | |
335 | if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame( |
336 | Other: NodeKind)) { |
337 | auto NNSLA = getUnchecked<NestedNameSpecifierLoc>(); |
338 | auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>(); |
339 | return std::make_pair(NNSLA.getNestedNameSpecifier(), |
340 | NNSLA.getOpaqueData()) < |
341 | std::make_pair(NNSLB.getNestedNameSpecifier(), |
342 | NNSLB.getOpaqueData()); |
343 | } |
344 | |
345 | assert(getMemoizationData() && Other.getMemoizationData()); |
346 | return getMemoizationData() < Other.getMemoizationData(); |
347 | } |
348 | bool operator==(const DynTypedNode &Other) const { |
349 | // DynTypedNode::create() stores the exact kind of the node in NodeKind. |
350 | // If they contain the same node, their NodeKind must be the same. |
351 | if (!NodeKind.isSame(Other: Other.NodeKind)) |
352 | return false; |
353 | |
354 | // FIXME: Implement for other types. |
355 | if (ASTNodeKind::getFromNodeKind<QualType>().isSame(Other: NodeKind)) |
356 | return getUnchecked<QualType>() == Other.getUnchecked<QualType>(); |
357 | |
358 | if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(Other: NodeKind)) |
359 | return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>(); |
360 | |
361 | if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(Other: NodeKind)) |
362 | return getUnchecked<NestedNameSpecifierLoc>() == |
363 | Other.getUnchecked<NestedNameSpecifierLoc>(); |
364 | |
365 | assert(getMemoizationData() && Other.getMemoizationData()); |
366 | return getMemoizationData() == Other.getMemoizationData(); |
367 | } |
368 | bool operator!=(const DynTypedNode &Other) const { |
369 | return !operator==(Other); |
370 | } |
371 | /// @} |
372 | |
373 | /// Hooks for using DynTypedNode as a key in a DenseMap. |
374 | struct DenseMapInfo { |
375 | static inline DynTypedNode getEmptyKey() { |
376 | DynTypedNode Node; |
377 | Node.NodeKind = ASTNodeKind::DenseMapInfo::getEmptyKey(); |
378 | return Node; |
379 | } |
380 | static inline DynTypedNode getTombstoneKey() { |
381 | DynTypedNode Node; |
382 | Node.NodeKind = ASTNodeKind::DenseMapInfo::getTombstoneKey(); |
383 | return Node; |
384 | } |
385 | static unsigned getHashValue(const DynTypedNode &Val) { |
386 | // FIXME: Add hashing support for the remaining types. |
387 | if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(Other: Val.NodeKind)) { |
388 | auto TL = Val.getUnchecked<TypeLoc>(); |
389 | return llvm::hash_combine(TL.getType().getAsOpaquePtr(), |
390 | TL.getOpaqueData()); |
391 | } |
392 | |
393 | if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame( |
394 | Other: Val.NodeKind)) { |
395 | auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>(); |
396 | return llvm::hash_combine(NNSL.getNestedNameSpecifier(), |
397 | NNSL.getOpaqueData()); |
398 | } |
399 | |
400 | assert(Val.getMemoizationData()); |
401 | return llvm::hash_value(Val.getMemoizationData()); |
402 | } |
403 | static bool isEqual(const DynTypedNode &LHS, const DynTypedNode &RHS) { |
404 | auto Empty = ASTNodeKind::DenseMapInfo::getEmptyKey(); |
405 | auto TombStone = ASTNodeKind::DenseMapInfo::getTombstoneKey(); |
406 | return (ASTNodeKind::DenseMapInfo::isEqual(LHS: LHS.NodeKind, RHS: Empty) && |
407 | ASTNodeKind::DenseMapInfo::isEqual(LHS: RHS.NodeKind, RHS: Empty)) || |
408 | (ASTNodeKind::DenseMapInfo::isEqual(LHS: LHS.NodeKind, RHS: TombStone) && |
409 | ASTNodeKind::DenseMapInfo::isEqual(LHS: RHS.NodeKind, RHS: TombStone)) || |
410 | LHS == RHS; |
411 | } |
412 | }; |
413 | |
414 | private: |
415 | /// Takes care of converting from and to \c T. |
416 | template <typename T, typename EnablerT = void> struct BaseConverter; |
417 | |
418 | /// Converter that uses dyn_cast<T> from a stored BaseT*. |
419 | template <typename T, typename BaseT> struct DynCastPtrConverter { |
420 | static const T *get(ASTNodeKind NodeKind, const void *Storage) { |
421 | if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)) |
422 | return &getUnchecked(NodeKind, Storage); |
423 | return nullptr; |
424 | } |
425 | static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { |
426 | assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)); |
427 | return *cast<T>(static_cast<const BaseT *>( |
428 | *reinterpret_cast<const void *const *>(Storage))); |
429 | } |
430 | static DynTypedNode create(const BaseT &Node) { |
431 | DynTypedNode Result; |
432 | Result.NodeKind = ASTNodeKind::getFromNode(Node); |
433 | new (&Result.Storage) const void *(&Node); |
434 | return Result; |
435 | } |
436 | }; |
437 | |
438 | /// Converter that stores T* (by pointer). |
439 | template <typename T> struct PtrConverter { |
440 | static const T *get(ASTNodeKind NodeKind, const void *Storage) { |
441 | if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)) |
442 | return &getUnchecked(NodeKind, Storage); |
443 | return nullptr; |
444 | } |
445 | static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { |
446 | assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)); |
447 | return *static_cast<const T *>( |
448 | *reinterpret_cast<const void *const *>(Storage)); |
449 | } |
450 | static DynTypedNode create(const T &Node) { |
451 | DynTypedNode Result; |
452 | Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); |
453 | new (&Result.Storage) const void *(&Node); |
454 | return Result; |
455 | } |
456 | }; |
457 | |
458 | /// Converter that stores T (by value). |
459 | template <typename T> struct ValueConverter { |
460 | static const T *get(ASTNodeKind NodeKind, const void *Storage) { |
461 | if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)) |
462 | return reinterpret_cast<const T *>(Storage); |
463 | return nullptr; |
464 | } |
465 | static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { |
466 | assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)); |
467 | return *reinterpret_cast<const T *>(Storage); |
468 | } |
469 | static DynTypedNode create(const T &Node) { |
470 | DynTypedNode Result; |
471 | Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); |
472 | new (&Result.Storage) T(Node); |
473 | return Result; |
474 | } |
475 | }; |
476 | |
477 | /// Converter that stores nodes by value. It must be possible to dynamically |
478 | /// cast the stored node within a type hierarchy without breaking (especially |
479 | /// through slicing). |
480 | template <typename T, typename BaseT, |
481 | typename = std::enable_if_t<(sizeof(T) == sizeof(BaseT))>> |
482 | struct DynCastValueConverter { |
483 | static const T *get(ASTNodeKind NodeKind, const void *Storage) { |
484 | if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)) |
485 | return &getUnchecked(NodeKind, Storage); |
486 | return nullptr; |
487 | } |
488 | static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { |
489 | assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)); |
490 | return *static_cast<const T *>(reinterpret_cast<const BaseT *>(Storage)); |
491 | } |
492 | static DynTypedNode create(const T &Node) { |
493 | DynTypedNode Result; |
494 | Result.NodeKind = ASTNodeKind::getFromNode(Node); |
495 | new (&Result.Storage) T(Node); |
496 | return Result; |
497 | } |
498 | }; |
499 | |
500 | ASTNodeKind NodeKind; |
501 | |
502 | /// Stores the data of the node. |
503 | /// |
504 | /// Note that we can store \c Decls, \c Stmts, \c Types, |
505 | /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are |
506 | /// guaranteed to be unique pointers pointing to dedicated storage in the AST. |
507 | /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs, |
508 | /// \c TemplateArguments and \c TemplateArgumentLocs on the other hand do not |
509 | /// have storage or unique pointers and thus need to be stored by value. |
510 | llvm::AlignedCharArrayUnion<const void *, TemplateArgument, |
511 | TemplateArgumentLoc, NestedNameSpecifierLoc, |
512 | QualType, TypeLoc, ObjCProtocolLoc> |
513 | Storage; |
514 | }; |
515 | |
516 | template <typename T> |
517 | struct DynTypedNode::BaseConverter< |
518 | T, std::enable_if_t<std::is_base_of<Decl, T>::value>> |
519 | : public DynCastPtrConverter<T, Decl> {}; |
520 | |
521 | template <typename T> |
522 | struct DynTypedNode::BaseConverter< |
523 | T, std::enable_if_t<std::is_base_of<Stmt, T>::value>> |
524 | : public DynCastPtrConverter<T, Stmt> {}; |
525 | |
526 | template <typename T> |
527 | struct DynTypedNode::BaseConverter< |
528 | T, std::enable_if_t<std::is_base_of<Type, T>::value>> |
529 | : public DynCastPtrConverter<T, Type> {}; |
530 | |
531 | template <typename T> |
532 | struct DynTypedNode::BaseConverter< |
533 | T, std::enable_if_t<std::is_base_of<OMPClause, T>::value>> |
534 | : public DynCastPtrConverter<T, OMPClause> {}; |
535 | |
536 | template <typename T> |
537 | struct DynTypedNode::BaseConverter< |
538 | T, std::enable_if_t<std::is_base_of<Attr, T>::value>> |
539 | : public DynCastPtrConverter<T, Attr> {}; |
540 | |
541 | template <> |
542 | struct DynTypedNode::BaseConverter< |
543 | NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {}; |
544 | |
545 | template <> |
546 | struct DynTypedNode::BaseConverter< |
547 | CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {}; |
548 | |
549 | template <> |
550 | struct DynTypedNode::BaseConverter< |
551 | TemplateArgument, void> : public ValueConverter<TemplateArgument> {}; |
552 | |
553 | template <> |
554 | struct DynTypedNode::BaseConverter<TemplateArgumentLoc, void> |
555 | : public ValueConverter<TemplateArgumentLoc> {}; |
556 | |
557 | template <> |
558 | struct DynTypedNode::BaseConverter<LambdaCapture, void> |
559 | : public ValueConverter<LambdaCapture> {}; |
560 | |
561 | template <> |
562 | struct DynTypedNode::BaseConverter< |
563 | TemplateName, void> : public ValueConverter<TemplateName> {}; |
564 | |
565 | template <> |
566 | struct DynTypedNode::BaseConverter< |
567 | NestedNameSpecifierLoc, |
568 | void> : public ValueConverter<NestedNameSpecifierLoc> {}; |
569 | |
570 | template <> |
571 | struct DynTypedNode::BaseConverter<QualType, |
572 | void> : public ValueConverter<QualType> {}; |
573 | |
574 | template <typename T> |
575 | struct DynTypedNode::BaseConverter< |
576 | T, std::enable_if_t<std::is_base_of<TypeLoc, T>::value>> |
577 | : public DynCastValueConverter<T, TypeLoc> {}; |
578 | |
579 | template <> |
580 | struct DynTypedNode::BaseConverter<CXXBaseSpecifier, void> |
581 | : public PtrConverter<CXXBaseSpecifier> {}; |
582 | |
583 | template <> |
584 | struct DynTypedNode::BaseConverter<ObjCProtocolLoc, void> |
585 | : public ValueConverter<ObjCProtocolLoc> {}; |
586 | |
587 | template <> |
588 | struct DynTypedNode::BaseConverter<ConceptReference, void> |
589 | : public PtrConverter<ConceptReference> {}; |
590 | |
591 | // The only operation we allow on unsupported types is \c get. |
592 | // This allows to conveniently use \c DynTypedNode when having an arbitrary |
593 | // AST node that is not supported, but prevents misuse - a user cannot create |
594 | // a DynTypedNode from arbitrary types. |
595 | template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { |
596 | static const T *get(ASTNodeKind NodeKind, const char Storage[]) { |
597 | return NULL; |
598 | } |
599 | }; |
600 | |
601 | } // end namespace clang |
602 | |
603 | namespace llvm { |
604 | |
605 | template <> |
606 | struct DenseMapInfo<clang::ASTNodeKind> : clang::ASTNodeKind::DenseMapInfo {}; |
607 | |
608 | template <> |
609 | struct DenseMapInfo<clang::DynTypedNode> : clang::DynTypedNode::DenseMapInfo {}; |
610 | |
611 | } // end namespace llvm |
612 | |
613 | #endif |
614 | |