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 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. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H 16 #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H 17 18 #include "clang/AST/Decl.h" 19 #include "clang/AST/Stmt.h" 20 #include "clang/AST/TypeLoc.h" 21 #include "llvm/Support/AlignOf.h" 22 23 namespace clang { 24 namespace ast_type_traits { 25 26 /// \brief A dynamically typed AST node container. 27 /// 28 /// Stores an AST node in a type safe way. This allows writing code that 29 /// works with different kinds of AST nodes, despite the fact that they don't 30 /// have a common base class. 31 /// 32 /// Use \c create(Node) to create a \c DynTypedNode from an AST node, 33 /// and \c get<T>() to retrieve the node as type T if the types match. 34 /// 35 /// See \c NodeTypeTag for which node base types are currently supported; 36 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of 37 /// the supported base types. 38 class DynTypedNode { 39 public: 40 /// \brief Creates a \c DynTypedNode from \c Node. 41 template <typename T> create(const T & Node)42 static DynTypedNode create(const T &Node) { 43 return BaseConverter<T>::create(Node); 44 } 45 46 /// \brief Retrieve the stored node as type \c T. 47 /// 48 /// Returns NULL if the stored node does not have a type that is 49 /// convertible to \c T. 50 /// 51 /// For types that have identity via their pointer in the AST 52 /// (like \c Stmt and \c Decl) the returned pointer points to the 53 /// referenced AST node. 54 /// For other types (like \c QualType) the value is stored directly 55 /// in the \c DynTypedNode, and the returned pointer points at 56 /// the storage inside DynTypedNode. For those nodes, do not 57 /// use the pointer outside the scope of the DynTypedNode. 58 template <typename T> get()59 const T *get() const { 60 return BaseConverter<T>::get(Tag, Storage.buffer); 61 } 62 63 /// \brief Returns a pointer that identifies the stored AST node. 64 /// 65 /// Note that this is not supported by all AST nodes. For AST nodes 66 /// that don't have a pointer-defined identity inside the AST, this 67 /// method returns NULL. 68 const void *getMemoizationData() const; 69 70 private: 71 /// \brief Takes care of converting from and to \c T. 72 template <typename T, typename EnablerT = void> struct BaseConverter; 73 74 /// \brief Supported base node types. 75 enum NodeTypeTag { 76 NT_Decl, 77 NT_Stmt, 78 NT_NestedNameSpecifier, 79 NT_NestedNameSpecifierLoc, 80 NT_QualType, 81 NT_Type, 82 NT_TypeLoc 83 } Tag; 84 85 /// \brief Stores the data of the node. 86 /// 87 /// Note that we can store \c Decls and \c Stmts by pointer as they are 88 /// guaranteed to be unique pointers pointing to dedicated storage in the 89 /// AST. \c QualTypes on the other hand do not have storage or unique 90 /// pointers and thus need to be stored by value. 91 llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier, 92 NestedNameSpecifierLoc, QualType, Type, 93 TypeLoc> Storage; 94 }; 95 96 // FIXME: Pull out abstraction for the following. 97 template<typename T> struct DynTypedNode::BaseConverter<T, 98 typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> { 99 static const T *get(NodeTypeTag Tag, const char Storage[]) { 100 if (Tag == NT_Decl) 101 return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage)); 102 return NULL; 103 } 104 static DynTypedNode create(const Decl &Node) { 105 DynTypedNode Result; 106 Result.Tag = NT_Decl; 107 new (Result.Storage.buffer) const Decl*(&Node); 108 return Result; 109 } 110 }; 111 template<typename T> struct DynTypedNode::BaseConverter<T, 112 typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> { 113 static const T *get(NodeTypeTag Tag, const char Storage[]) { 114 if (Tag == NT_Stmt) 115 return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage)); 116 return NULL; 117 } 118 static DynTypedNode create(const Stmt &Node) { 119 DynTypedNode Result; 120 Result.Tag = NT_Stmt; 121 new (Result.Storage.buffer) const Stmt*(&Node); 122 return Result; 123 } 124 }; 125 template<typename T> struct DynTypedNode::BaseConverter<T, 126 typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> { 127 static const T *get(NodeTypeTag Tag, const char Storage[]) { 128 if (Tag == NT_Type) 129 return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage)); 130 return NULL; 131 } 132 static DynTypedNode create(const Type &Node) { 133 DynTypedNode Result; 134 Result.Tag = NT_Type; 135 new (Result.Storage.buffer) const Type*(&Node); 136 return Result; 137 } 138 }; 139 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> { 140 static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) { 141 if (Tag == NT_NestedNameSpecifier) 142 return *reinterpret_cast<NestedNameSpecifier*const*>(Storage); 143 return NULL; 144 } 145 static DynTypedNode create(const NestedNameSpecifier &Node) { 146 DynTypedNode Result; 147 Result.Tag = NT_NestedNameSpecifier; 148 new (Result.Storage.buffer) const NestedNameSpecifier*(&Node); 149 return Result; 150 } 151 }; 152 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> { 153 static const NestedNameSpecifierLoc *get(NodeTypeTag Tag, 154 const char Storage[]) { 155 if (Tag == NT_NestedNameSpecifierLoc) 156 return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage); 157 return NULL; 158 } 159 static DynTypedNode create(const NestedNameSpecifierLoc &Node) { 160 DynTypedNode Result; 161 Result.Tag = NT_NestedNameSpecifierLoc; 162 new (Result.Storage.buffer) NestedNameSpecifierLoc(Node); 163 return Result; 164 } 165 }; 166 template<> struct DynTypedNode::BaseConverter<QualType, void> { 167 static const QualType *get(NodeTypeTag Tag, const char Storage[]) { 168 if (Tag == NT_QualType) 169 return reinterpret_cast<const QualType*>(Storage); 170 return NULL; 171 } 172 static DynTypedNode create(const QualType &Node) { 173 DynTypedNode Result; 174 Result.Tag = NT_QualType; 175 new (Result.Storage.buffer) QualType(Node); 176 return Result; 177 } 178 }; 179 template<> struct DynTypedNode::BaseConverter<TypeLoc, void> { 180 static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) { 181 if (Tag == NT_TypeLoc) 182 return reinterpret_cast<const TypeLoc*>(Storage); 183 return NULL; 184 } 185 static DynTypedNode create(const TypeLoc &Node) { 186 DynTypedNode Result; 187 Result.Tag = NT_TypeLoc; 188 new (Result.Storage.buffer) TypeLoc(Node); 189 return Result; 190 } 191 }; 192 // The only operation we allow on unsupported types is \c get. 193 // This allows to conveniently use \c DynTypedNode when having an arbitrary 194 // AST node that is not supported, but prevents misuse - a user cannot create 195 // a DynTypedNode from arbitrary types. 196 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { 197 static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; } 198 }; 199 200 inline const void *DynTypedNode::getMemoizationData() const { 201 switch (Tag) { 202 case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer); 203 case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer); 204 default: return NULL; 205 }; 206 } 207 208 } // end namespace ast_type_traits 209 } // end namespace clang 210 211 #endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H 212