1 //===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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
14 //===----------------------------------------------------------------------===//
16 #ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
17 #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
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"
29 namespace ast_type_traits {
31 /// \brief Kind identifier.
33 /// It can be constructed from any node kind and allows for runtime type
35 /// Use getFromNodeKind<T>() to construct them.
38 /// \brief Empty identifier. It matches nothing.
39 ASTNodeKind() : KindId(NKI_None) {}
41 /// \brief Construct an identifier for T.
43 static ASTNodeKind getFromNodeKind() {
44 return ASTNodeKind(KindToKindId<T>::Id);
47 /// \brief Returns \c true if \c this and \c Other represent the same kind.
48 bool isSame(ASTNodeKind Other) const;
50 /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
51 bool isBaseOf(ASTNodeKind Other) const;
53 /// \brief String representation of the kind.
54 StringRef asStringRef() const;
59 /// Includes all possible base and derived kinds.
62 NKI_CXXCtorInitializer,
64 NKI_NestedNameSpecifier,
65 NKI_NestedNameSpecifierLoc,
69 #define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
70 #include "clang/AST/DeclNodes.inc"
72 #define STMT(DERIVED, BASE) NKI_##DERIVED,
73 #include "clang/AST/StmtNodes.inc"
75 #define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
76 #include "clang/AST/TypeNodes.def"
80 /// \brief Use getFromNodeKind<T>() to construct the kind.
81 ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
83 /// \brief Returns \c true if \c Base is a base kind of (or same as) \c
85 static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
87 /// \brief Helper meta-function to convert a kind T to its enum value.
89 /// This struct is specialized below for all known kinds.
90 template <class T> struct KindToKindId {
91 static const NodeKindId Id = NKI_None;
94 /// \brief Per kind info.
96 /// \brief The id of the parent kind, or None if it has no parent.
98 /// \brief Name of the kind.
101 static const KindInfo AllKindInfo[NKI_NumberOfKinds];
106 #define KIND_TO_KIND_ID(Class) \
107 template <> struct ASTNodeKind::KindToKindId<Class> { \
108 static const NodeKindId Id = NKI_##Class; \
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
127 /// \brief A dynamically typed AST node container.
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.
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.
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.
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);
147 /// \brief Retrieve the stored node as type \c T.
149 /// Returns NULL if the stored node does not have a type that is
150 /// convertible to \c T.
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);
164 /// \brief Returns a pointer that identifies the stored AST node.
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;
172 /// \brief Imposes an order on \c DynTypedNode.
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();
181 bool operator==(const DynTypedNode &Other) const {
182 // Nodes with different types cannot be equal.
183 if (!NodeKind.isSame(Other.NodeKind))
186 // FIXME: Implement for other types.
187 if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
188 return *get<QualType>() == *Other.get<QualType>();
190 assert(getMemoizationData() && Other.getMemoizationData());
191 return getMemoizationData() == Other.getMemoizationData();
193 bool operator!=(const DynTypedNode &Other) const {
194 return !operator==(Other);
199 /// \brief Takes care of converting from and to \c T.
200 template <typename T, typename EnablerT = void> struct BaseConverter;
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));
209 static DynTypedNode create(const BaseT &Node) {
211 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
212 new (Result.Storage.buffer) const BaseT * (&Node);
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);
224 static DynTypedNode create(const T &Node) {
226 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
227 new (Result.Storage.buffer) const T * (&Node);
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);
239 static DynTypedNode create(const T &Node) {
241 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
242 new (Result.Storage.buffer) T(Node);
247 ASTNodeKind NodeKind;
249 /// \brief Stores the data of the node.
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 *>
260 llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
261 NestedNameSpecifierLoc, QualType, TypeLoc>
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> {};
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> {};
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> {};
281 struct DynTypedNode::BaseConverter<
282 NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
285 struct DynTypedNode::BaseConverter<
286 CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
289 struct DynTypedNode::BaseConverter<
290 TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
293 struct DynTypedNode::BaseConverter<
294 NestedNameSpecifierLoc,
295 void> : public ValueConverter<NestedNameSpecifierLoc> {};
298 struct DynTypedNode::BaseConverter<QualType,
299 void> : public ValueConverter<QualType> {};
302 struct DynTypedNode::BaseConverter<
303 TypeLoc, void> : public ValueConverter<TypeLoc> {};
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[]) {
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);
328 } // end namespace ast_type_traits
329 } // end namespace clang
331 #endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H