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 332