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