]> granicus.if.org Git - clang/blob - include/clang/AST/ASTTypeTraits.h
Add more types to ASTNodeKind. Refactor common instantiation code.
[clang] / include / clang / AST / ASTTypeTraits.h
1 //===--- ASTTypeTraits.h ----------------------------------------*- 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 //  Provides a dynamic type identifier and a dynamically typed node container
11 //  that can be used to store an AST base node at runtime in the same storage in
12 //  a type safe way.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
17 #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
18
19 #include "clang/AST/ASTFwd.h"
20 #include "clang/AST/Decl.h"
21 #include "clang/AST/NestedNameSpecifier.h"
22 #include "clang/AST/Stmt.h"
23 #include "clang/AST/TemplateBase.h"
24 #include "clang/AST/TypeLoc.h"
25 #include "clang/Basic/LLVM.h"
26 #include "llvm/Support/AlignOf.h"
27
28 namespace clang {
29 namespace ast_type_traits {
30
31 /// \brief Kind identifier.
32 ///
33 /// It can be constructed from any node kind and allows for runtime type
34 /// hierarchy checks.
35 /// Use getFromNodeKind<T>() to construct them.
36 class ASTNodeKind {
37 public:
38   /// \brief Empty identifier. It matches nothing.
39   ASTNodeKind() : KindId(NKI_None) {}
40
41   /// \brief Construct an identifier for T.
42   template <class T>
43   static ASTNodeKind getFromNodeKind() {
44     return ASTNodeKind(KindToKindId<T>::Id);
45   }
46
47   /// \brief Returns \c true if \c this and \c Other represent the same kind.
48   bool isSame(ASTNodeKind Other) const;
49
50   /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
51   bool isBaseOf(ASTNodeKind Other) const;
52
53   /// \brief String representation of the kind.
54   StringRef asStringRef() const;
55
56 private:
57   /// \brief Kind ids.
58   ///
59   /// Includes all possible base and derived kinds.
60   enum NodeKindId {
61     NKI_None,
62     NKI_CXXCtorInitializer,
63     NKI_TemplateArgument,
64     NKI_NestedNameSpecifier,
65     NKI_NestedNameSpecifierLoc,
66     NKI_QualType,
67     NKI_TypeLoc,
68     NKI_Decl,
69 #define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
70 #include "clang/AST/DeclNodes.inc"
71     NKI_Stmt,
72 #define STMT(DERIVED, BASE) NKI_##DERIVED,
73 #include "clang/AST/StmtNodes.inc"
74     NKI_Type,
75 #define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
76 #include "clang/AST/TypeNodes.def"
77     NKI_NumberOfKinds
78   };
79
80   /// \brief Use getFromNodeKind<T>() to construct the kind.
81   ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
82
83   /// \brief Returns \c true if \c Base is a base kind of (or same as) \c
84   ///   Derived.
85   static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
86
87   /// \brief Helper meta-function to convert a kind T to its enum value.
88   ///
89   /// This struct is specialized below for all known kinds.
90   template <class T> struct KindToKindId {
91     static const NodeKindId Id = NKI_None;
92   };
93
94   /// \brief Per kind info.
95   struct KindInfo {
96     /// \brief The id of the parent kind, or None if it has no parent.
97     NodeKindId ParentId;
98     /// \brief Name of the kind.
99     const char *Name;
100   };
101   static const KindInfo AllKindInfo[NKI_NumberOfKinds];
102
103   NodeKindId KindId;
104 };
105
106 #define KIND_TO_KIND_ID(Class)                                                 \
107   template <> struct ASTNodeKind::KindToKindId<Class> {                        \
108     static const NodeKindId Id = NKI_##Class;                                  \
109   };
110 KIND_TO_KIND_ID(CXXCtorInitializer)
111 KIND_TO_KIND_ID(TemplateArgument)
112 KIND_TO_KIND_ID(NestedNameSpecifier)
113 KIND_TO_KIND_ID(NestedNameSpecifierLoc)
114 KIND_TO_KIND_ID(QualType)
115 KIND_TO_KIND_ID(TypeLoc)
116 KIND_TO_KIND_ID(Decl)
117 KIND_TO_KIND_ID(Stmt)
118 KIND_TO_KIND_ID(Type)
119 #define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
120 #include "clang/AST/DeclNodes.inc"
121 #define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
122 #include "clang/AST/StmtNodes.inc"
123 #define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
124 #include "clang/AST/TypeNodes.def"
125 #undef KIND_TO_KIND_ID
126
127 /// \brief A dynamically typed AST node container.
128 ///
129 /// Stores an AST node in a type safe way. This allows writing code that
130 /// works with different kinds of AST nodes, despite the fact that they don't
131 /// have a common base class.
132 ///
133 /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
134 /// and \c get<T>() to retrieve the node as type T if the types match.
135 ///
136 /// See \c ASTNodeKind for which node base types are currently supported;
137 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
138 /// the supported base types.
139 class DynTypedNode {
140 public:
141   /// \brief Creates a \c DynTypedNode from \c Node.
142   template <typename T>
143   static DynTypedNode create(const T &Node) {
144     return BaseConverter<T>::create(Node);
145   }
146
147   /// \brief Retrieve the stored node as type \c T.
148   ///
149   /// Returns NULL if the stored node does not have a type that is
150   /// convertible to \c T.
151   ///
152   /// For types that have identity via their pointer in the AST
153   /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
154   /// pointer points to the referenced AST node.
155   /// For other types (like \c QualType) the value is stored directly
156   /// in the \c DynTypedNode, and the returned pointer points at
157   /// the storage inside DynTypedNode. For those nodes, do not
158   /// use the pointer outside the scope of the DynTypedNode.
159   template <typename T>
160   const T *get() const {
161     return BaseConverter<T>::get(NodeKind, Storage.buffer);
162   }
163
164   /// \brief Returns a pointer that identifies the stored AST node.
165   ///
166   /// Note that this is not supported by all AST nodes. For AST nodes
167   /// that don't have a pointer-defined identity inside the AST, this
168   /// method returns NULL.
169   const void *getMemoizationData() const;
170
171   /// @{
172   /// \brief Imposes an order on \c DynTypedNode.
173   ///
174   /// Supports comparison of nodes that support memoization.
175   /// FIXME: Implement comparsion for other node types (currently
176   /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
177   bool operator<(const DynTypedNode &Other) const {
178     assert(getMemoizationData() && Other.getMemoizationData());
179     return getMemoizationData() < Other.getMemoizationData();
180   }
181   bool operator==(const DynTypedNode &Other) const {
182     // Nodes with different types cannot be equal.
183     if (!NodeKind.isSame(Other.NodeKind))
184       return false;
185
186     // FIXME: Implement for other types.
187     if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
188       return *get<QualType>() == *Other.get<QualType>();
189     }
190     assert(getMemoizationData() && Other.getMemoizationData());
191     return getMemoizationData() == Other.getMemoizationData();
192   }
193   bool operator!=(const DynTypedNode &Other) const {
194     return !operator==(Other);
195   }
196   /// @}
197
198 private:
199   /// \brief Takes care of converting from and to \c T.
200   template <typename T, typename EnablerT = void> struct BaseConverter;
201
202   /// \brief Converter that uses dyn_cast<T> from a stored BaseT*.
203   template <typename T, typename BaseT> struct DynCastPtrConverter {
204     static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
205       if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
206         return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
207       return NULL;
208     }
209     static DynTypedNode create(const BaseT &Node) {
210       DynTypedNode Result;
211       Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
212       new (Result.Storage.buffer) const BaseT * (&Node);
213       return Result;
214     }
215   };
216
217   /// \brief Converter that stores T* (by pointer).
218   template <typename T> struct PtrConverter {
219     static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
220       if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
221         return *reinterpret_cast<T *const *>(Storage);
222       return NULL;
223     }
224     static DynTypedNode create(const T &Node) {
225       DynTypedNode Result;
226       Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
227       new (Result.Storage.buffer) const T * (&Node);
228       return Result;
229     }
230   };
231
232   /// \brief Converter that stores T (by value).
233   template <typename T> struct ValueConverter {
234     static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
235       if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
236         return reinterpret_cast<const T *>(Storage);
237       return NULL;
238     }
239     static DynTypedNode create(const T &Node) {
240       DynTypedNode Result;
241       Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
242       new (Result.Storage.buffer) T(Node);
243       return Result;
244     }
245   };
246
247   ASTNodeKind NodeKind;
248
249   /// \brief Stores the data of the node.
250   ///
251   /// Note that we can store \c Decls, \c Stmts, \c Types,
252   /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
253   /// guaranteed to be unique pointers pointing to dedicated storage in the AST.
254   /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and
255   /// \c TemplateArguments on the other hand do not have storage or unique
256   /// pointers and thus need to be stored by value.
257   typedef llvm::AlignedCharArrayUnion<
258       Decl *, Stmt *, Type *, NestedNameSpecifier *, CXXCtorInitializer *>
259       KindsByPointer;
260   llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
261                               NestedNameSpecifierLoc, QualType, TypeLoc>
262       Storage;
263 };
264
265 template <typename T>
266 struct DynTypedNode::BaseConverter<
267     T, typename llvm::enable_if<llvm::is_base_of<
268            Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {};
269
270 template <typename T>
271 struct DynTypedNode::BaseConverter<
272     T, typename llvm::enable_if<llvm::is_base_of<
273            Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {};
274
275 template <typename T>
276 struct DynTypedNode::BaseConverter<
277     T, typename llvm::enable_if<llvm::is_base_of<
278            Type, T> >::type> : public DynCastPtrConverter<T, Type> {};
279
280 template <>
281 struct DynTypedNode::BaseConverter<
282     NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
283
284 template <>
285 struct DynTypedNode::BaseConverter<
286     CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
287
288 template <>
289 struct DynTypedNode::BaseConverter<
290     TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
291
292 template <>
293 struct DynTypedNode::BaseConverter<
294     NestedNameSpecifierLoc,
295     void> : public ValueConverter<NestedNameSpecifierLoc> {};
296
297 template <>
298 struct DynTypedNode::BaseConverter<QualType,
299                                    void> : public ValueConverter<QualType> {};
300
301 template <>
302 struct DynTypedNode::BaseConverter<
303     TypeLoc, void> : public ValueConverter<TypeLoc> {};
304
305 // The only operation we allow on unsupported types is \c get.
306 // This allows to conveniently use \c DynTypedNode when having an arbitrary
307 // AST node that is not supported, but prevents misuse - a user cannot create
308 // a DynTypedNode from arbitrary types.
309 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
310   static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
311     return NULL;
312   }
313 };
314
315 inline const void *DynTypedNode::getMemoizationData() const {
316   if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
317     return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
318   } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
319     return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
320   } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) {
321     return BaseConverter<Type>::get(NodeKind, Storage.buffer);
322   } else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
323     return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
324   }
325   return NULL;
326 }
327
328 } // end namespace ast_type_traits
329 } // end namespace clang
330
331 #endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H