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"
36 struct PrintingPolicy;
38 namespace ast_type_traits {
40 /// \brief Kind identifier.
42 /// It can be constructed from any node kind and allows for runtime type
44 /// Use getFromNodeKind<T>() to construct them.
47 /// \brief Empty identifier. It matches nothing.
48 ASTNodeKind() : KindId(NKI_None) {}
50 /// \brief Construct an identifier for T.
52 static ASTNodeKind getFromNodeKind() {
53 return ASTNodeKind(KindToKindId<T>::Id);
56 /// \brief Returns \c true if \c this and \c Other represent the same kind.
57 bool isSame(ASTNodeKind Other) const;
59 /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other.
60 bool isBaseOf(ASTNodeKind Other) const;
62 /// \brief String representation of the kind.
63 StringRef asStringRef() const;
68 /// Includes all possible base and derived kinds.
71 NKI_CXXCtorInitializer,
73 NKI_NestedNameSpecifier,
74 NKI_NestedNameSpecifierLoc,
78 #define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
79 #include "clang/AST/DeclNodes.inc"
81 #define STMT(DERIVED, BASE) NKI_##DERIVED,
82 #include "clang/AST/StmtNodes.inc"
84 #define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
85 #include "clang/AST/TypeNodes.def"
89 /// \brief Use getFromNodeKind<T>() to construct the kind.
90 ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
92 /// \brief Returns \c true if \c Base is a base kind of (or same as) \c
94 static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
96 /// \brief Helper meta-function to convert a kind T to its enum value.
98 /// This struct is specialized below for all known kinds.
99 template <class T> struct KindToKindId {
100 static const NodeKindId Id = NKI_None;
103 /// \brief Per kind info.
105 /// \brief The id of the parent kind, or None if it has no parent.
107 /// \brief Name of the kind.
110 static const KindInfo AllKindInfo[NKI_NumberOfKinds];
115 #define KIND_TO_KIND_ID(Class) \
116 template <> struct ASTNodeKind::KindToKindId<Class> { \
117 static const NodeKindId Id = NKI_##Class; \
119 KIND_TO_KIND_ID(CXXCtorInitializer)
120 KIND_TO_KIND_ID(TemplateArgument)
121 KIND_TO_KIND_ID(NestedNameSpecifier)
122 KIND_TO_KIND_ID(NestedNameSpecifierLoc)
123 KIND_TO_KIND_ID(QualType)
124 KIND_TO_KIND_ID(TypeLoc)
125 KIND_TO_KIND_ID(Decl)
126 KIND_TO_KIND_ID(Stmt)
127 KIND_TO_KIND_ID(Type)
128 #define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
129 #include "clang/AST/DeclNodes.inc"
130 #define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
131 #include "clang/AST/StmtNodes.inc"
132 #define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
133 #include "clang/AST/TypeNodes.def"
134 #undef KIND_TO_KIND_ID
136 /// \brief A dynamically typed AST node container.
138 /// Stores an AST node in a type safe way. This allows writing code that
139 /// works with different kinds of AST nodes, despite the fact that they don't
140 /// have a common base class.
142 /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
143 /// and \c get<T>() to retrieve the node as type T if the types match.
145 /// See \c ASTNodeKind for which node base types are currently supported;
146 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
147 /// the supported base types.
150 /// \brief Creates a \c DynTypedNode from \c Node.
151 template <typename T>
152 static DynTypedNode create(const T &Node) {
153 return BaseConverter<T>::create(Node);
156 /// \brief Retrieve the stored node as type \c T.
158 /// Returns NULL if the stored node does not have a type that is
159 /// convertible to \c T.
161 /// For types that have identity via their pointer in the AST
162 /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
163 /// pointer points to the referenced AST node.
164 /// For other types (like \c QualType) the value is stored directly
165 /// in the \c DynTypedNode, and the returned pointer points at
166 /// the storage inside DynTypedNode. For those nodes, do not
167 /// use the pointer outside the scope of the DynTypedNode.
168 template <typename T>
169 const T *get() const {
170 return BaseConverter<T>::get(NodeKind, Storage.buffer);
173 /// \brief Returns a pointer that identifies the stored AST node.
175 /// Note that this is not supported by all AST nodes. For AST nodes
176 /// that don't have a pointer-defined identity inside the AST, this
177 /// method returns NULL.
178 const void *getMemoizationData() const;
180 /// \brief Prints the node to the given output stream.
181 void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
183 /// \brief Dumps the node to the given output stream.
184 void dump(llvm::raw_ostream &OS, SourceManager &SM) const;
186 /// \brief For nodes which represent textual entities in the source code,
187 /// return their SourceRange. For all other nodes, return SourceRange().
188 SourceRange getSourceRange() const;
191 /// \brief Imposes an order on \c DynTypedNode.
193 /// Supports comparison of nodes that support memoization.
194 /// FIXME: Implement comparsion for other node types (currently
195 /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
196 bool operator<(const DynTypedNode &Other) const {
197 assert(getMemoizationData() && Other.getMemoizationData());
198 return getMemoizationData() < Other.getMemoizationData();
200 bool operator==(const DynTypedNode &Other) const {
201 // Nodes with different types cannot be equal.
202 if (!NodeKind.isSame(Other.NodeKind))
205 // FIXME: Implement for other types.
206 if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) {
207 return *get<QualType>() == *Other.get<QualType>();
209 assert(getMemoizationData() && Other.getMemoizationData());
210 return getMemoizationData() == Other.getMemoizationData();
212 bool operator!=(const DynTypedNode &Other) const {
213 return !operator==(Other);
218 /// \brief Takes care of converting from and to \c T.
219 template <typename T, typename EnablerT = void> struct BaseConverter;
221 /// \brief Converter that uses dyn_cast<T> from a stored BaseT*.
222 template <typename T, typename BaseT> struct DynCastPtrConverter {
223 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
224 if (ASTNodeKind::getFromNodeKind<BaseT>().isBaseOf(NodeKind))
225 return dyn_cast<T>(*reinterpret_cast<BaseT *const *>(Storage));
228 static DynTypedNode create(const BaseT &Node) {
230 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
231 new (Result.Storage.buffer) const BaseT * (&Node);
236 /// \brief Converter that stores T* (by pointer).
237 template <typename T> struct PtrConverter {
238 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
239 if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
240 return *reinterpret_cast<T *const *>(Storage);
243 static DynTypedNode create(const T &Node) {
245 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
246 new (Result.Storage.buffer) const T * (&Node);
251 /// \brief Converter that stores T (by value).
252 template <typename T> struct ValueConverter {
253 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
254 if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
255 return reinterpret_cast<const T *>(Storage);
258 static DynTypedNode create(const T &Node) {
260 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
261 new (Result.Storage.buffer) T(Node);
266 ASTNodeKind NodeKind;
268 /// \brief Stores the data of the node.
270 /// Note that we can store \c Decls, \c Stmts, \c Types,
271 /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
272 /// guaranteed to be unique pointers pointing to dedicated storage in the AST.
273 /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and
274 /// \c TemplateArguments on the other hand do not have storage or unique
275 /// pointers and thus need to be stored by value.
276 typedef llvm::AlignedCharArrayUnion<
277 Decl *, Stmt *, Type *, NestedNameSpecifier *, CXXCtorInitializer *>
279 llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument,
280 NestedNameSpecifierLoc, QualType, TypeLoc>
284 template <typename T>
285 struct DynTypedNode::BaseConverter<
286 T, typename llvm::enable_if<llvm::is_base_of<
287 Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {};
289 template <typename T>
290 struct DynTypedNode::BaseConverter<
291 T, typename llvm::enable_if<llvm::is_base_of<
292 Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {};
294 template <typename T>
295 struct DynTypedNode::BaseConverter<
296 T, typename llvm::enable_if<llvm::is_base_of<
297 Type, T> >::type> : public DynCastPtrConverter<T, Type> {};
300 struct DynTypedNode::BaseConverter<
301 NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
304 struct DynTypedNode::BaseConverter<
305 CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
308 struct DynTypedNode::BaseConverter<
309 TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
312 struct DynTypedNode::BaseConverter<
313 NestedNameSpecifierLoc,
314 void> : public ValueConverter<NestedNameSpecifierLoc> {};
317 struct DynTypedNode::BaseConverter<QualType,
318 void> : public ValueConverter<QualType> {};
321 struct DynTypedNode::BaseConverter<
322 TypeLoc, void> : public ValueConverter<TypeLoc> {};
324 // The only operation we allow on unsupported types is \c get.
325 // This allows to conveniently use \c DynTypedNode when having an arbitrary
326 // AST node that is not supported, but prevents misuse - a user cannot create
327 // a DynTypedNode from arbitrary types.
328 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
329 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
334 inline const void *DynTypedNode::getMemoizationData() const {
335 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) {
336 return BaseConverter<Decl>::get(NodeKind, Storage.buffer);
337 } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) {
338 return BaseConverter<Stmt>::get(NodeKind, Storage.buffer);
339 } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) {
340 return BaseConverter<Type>::get(NodeKind, Storage.buffer);
341 } else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) {
342 return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer);
347 } // end namespace ast_type_traits
348 } // end namespace clang
350 #endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H