1 //===--- ASTMatchersTypeTraits.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 dynamically typed node container that can be used to store
11 // an AST base node at runtime in the same storage in a type safe way.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
16 #define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/Stmt.h"
20 #include "llvm/Support/AlignOf.h"
23 namespace ast_type_traits {
25 /// \brief A dynamically typed AST node container.
27 /// Stores an AST node in a type safe way. This allows writing code that
28 /// works with different kinds of AST nodes, despite the fact that they don't
29 /// have a common base class.
31 /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
32 /// and \c get<T>() to retrieve the node as type T if the types match.
34 /// See \c NodeTypeTag for which node base types are currently supported;
35 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
36 /// the supported base types.
39 /// \brief Creates a \c DynTypedNode from \c Node.
41 static DynTypedNode create(const T &Node) {
42 return BaseConverter<T>::create(Node);
45 /// \brief Retrieve the stored node as type \c T.
47 /// Returns NULL if the stored node does not have a type that is
48 /// convertible to \c T.
50 /// For types that have identity via their pointer in the AST
51 /// (like \c Stmt and \c Decl) the returned pointer points to the
52 /// referenced AST node.
53 /// For other types (like \c QualType) the value is stored directly
54 /// in the \c DynTypedNode, and the returned pointer points at
55 /// the storage inside DynTypedNode. For those nodes, do not
56 /// use the pointer outside the scope of the DynTypedNode.
58 const T *get() const {
59 return BaseConverter<T>::get(Tag, Storage.buffer);
62 /// \brief Returns a pointer that identifies the stored AST node.
64 /// Note that this is not supported by all AST nodes. For AST nodes
65 /// that don't have a pointer-defined identity inside the AST, this
66 /// method returns NULL.
67 const void *getMemoizationData() const;
70 /// \brief Takes care of converting from and to \c T.
71 template <typename T, typename EnablerT = void> struct BaseConverter;
73 /// \brief Supported base node types.
77 NT_NestedNameSpecifier,
78 NT_NestedNameSpecifierLoc,
84 /// \brief Stores the data of the node.
86 /// Note that we can store \c Decls and \c Stmts by pointer as they are
87 /// guaranteed to be unique pointers pointing to dedicated storage in the
88 /// AST. \c QualTypes on the other hand do not have storage or unique
89 /// pointers and thus need to be stored by value.
90 llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc>
94 // FIXME: Pull out abstraction for the following.
95 template<typename T> struct DynTypedNode::BaseConverter<T,
96 typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
97 static const T *get(NodeTypeTag Tag, const char Storage[]) {
99 return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
102 static DynTypedNode create(const Decl &Node) {
104 Result.Tag = NT_Decl;
105 new (Result.Storage.buffer) const Decl*(&Node);
109 template<typename T> struct DynTypedNode::BaseConverter<T,
110 typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
111 static const T *get(NodeTypeTag Tag, const char Storage[]) {
113 return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
116 static DynTypedNode create(const Stmt &Node) {
118 Result.Tag = NT_Stmt;
119 new (Result.Storage.buffer) const Stmt*(&Node);
123 template<typename T> struct DynTypedNode::BaseConverter<T,
124 typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
125 static const T *get(NodeTypeTag Tag, const char Storage[]) {
127 return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
130 static DynTypedNode create(const Type &Node) {
132 Result.Tag = NT_Type;
133 new (Result.Storage.buffer) const Type*(&Node);
137 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
138 static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
139 if (Tag == NT_NestedNameSpecifier)
140 return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
143 static DynTypedNode create(const NestedNameSpecifier &Node) {
145 Result.Tag = NT_NestedNameSpecifier;
146 new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
150 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
151 static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
152 const char Storage[]) {
153 if (Tag == NT_NestedNameSpecifierLoc)
154 return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
157 static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
159 Result.Tag = NT_NestedNameSpecifierLoc;
160 new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
164 template<> struct DynTypedNode::BaseConverter<QualType, void> {
165 static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
166 if (Tag == NT_QualType)
167 return reinterpret_cast<const QualType*>(Storage);
170 static DynTypedNode create(const QualType &Node) {
172 Result.Tag = NT_QualType;
173 new (Result.Storage.buffer) QualType(Node);
177 template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
178 static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
179 if (Tag == NT_TypeLoc)
180 return reinterpret_cast<const TypeLoc*>(Storage);
183 static DynTypedNode create(const TypeLoc &Node) {
185 Result.Tag = NT_TypeLoc;
186 new (Result.Storage.buffer) TypeLoc(Node);
190 // The only operation we allow on unsupported types is \c get.
191 // This allows to conveniently use \c DynTypedNode when having an arbitrary
192 // AST node that is not supported, but prevents misuse - a user cannot create
193 // a DynTypedNode from arbitrary types.
194 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
195 static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
198 inline const void *DynTypedNode::getMemoizationData() const {
200 case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
201 case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
202 default: return NULL;
206 } // end namespace ast_type_traits
207 } // end namespace clang
209 #endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H