ASTTypeTraits.h revision cf52ca6bb6dd76a1bd967bc422287fafafa1e45a
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/Stmt.h" 22#include "clang/AST/TypeLoc.h" 23#include "clang/Basic/LLVM.h" 24#include "llvm/Support/AlignOf.h" 25 26namespace clang { 27namespace ast_type_traits { 28 29/// \brief Kind identifier. 30/// 31/// It can be constructed from any node kind and allows for runtime type 32/// hierarchy checks. 33/// Use getFromNodeKind<T>() to construct them. 34class ASTNodeKind { 35public: 36 /// \brief Empty identifier. It matches nothing. 37 ASTNodeKind() : KindId(NKI_None) {} 38 39 /// \brief Construct an identifier for T. 40 template <class T> 41 static ASTNodeKind getFromNodeKind() { 42 return ASTNodeKind(KindToKindId<T>::Id); 43 } 44 45 /// \brief Returns \c true if \c this and \c Other represent the same kind. 46 bool isSame(ASTNodeKind Other) const; 47 48 /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other 49 bool isBaseOf(ASTNodeKind Other) const; 50 51 /// \brief String representation of the kind. 52 StringRef asStringRef() const; 53 54private: 55 /// \brief Kind ids. 56 /// 57 /// Includes all possible base and derived kinds. 58 enum NodeKindId { 59 NKI_None, 60 NKI_NestedNameSpecifier, 61 NKI_NestedNameSpecifierLoc, 62 NKI_QualType, 63 NKI_TypeLoc, 64 NKI_Decl, 65#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl, 66#include "clang/AST/DeclNodes.inc" 67 NKI_Stmt, 68#define STMT(DERIVED, BASE) NKI_##DERIVED, 69#include "clang/AST/StmtNodes.inc" 70 NKI_Type, 71#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type, 72#include "clang/AST/TypeNodes.def" 73 NKI_NumberOfKinds 74 }; 75 76 /// \brief Use getFromNodeKind<T>() to construct the kind. 77 ASTNodeKind(NodeKindId KindId) : KindId(KindId) {} 78 79 /// \brief Returns \c true if \c Base is a base kind of (or same as) \c 80 /// Derived 81 static bool isBaseOf(NodeKindId Base, NodeKindId Derived); 82 83 /// \brief Helper meta-function to convert a kind T to its enum value. 84 /// 85 /// This struct is specialized below for all known kinds. 86 template <class T> struct KindToKindId { 87 static const NodeKindId Id = NKI_None; 88 }; 89 90 /// \brief Per kind info. 91 struct KindInfo { 92 /// \brief The id of the parent kind, or None if it has no parent. 93 NodeKindId ParentId; 94 /// \brief Name of the kind. 95 const char *Name; 96 }; 97 static const KindInfo AllKindInfo[NKI_NumberOfKinds]; 98 99 NodeKindId KindId; 100}; 101 102#define KIND_TO_KIND_ID(Class) \ 103 template <> struct ASTNodeKind::KindToKindId<Class> { \ 104 static const NodeKindId Id = NKI_##Class; \ 105 }; 106KIND_TO_KIND_ID(NestedNameSpecifier) 107KIND_TO_KIND_ID(NestedNameSpecifierLoc) 108KIND_TO_KIND_ID(QualType) 109KIND_TO_KIND_ID(TypeLoc) 110KIND_TO_KIND_ID(Decl) 111KIND_TO_KIND_ID(Stmt) 112KIND_TO_KIND_ID(Type) 113#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl) 114#include "clang/AST/DeclNodes.inc" 115#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED) 116#include "clang/AST/StmtNodes.inc" 117#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type) 118#include "clang/AST/TypeNodes.def" 119#undef KIND_TO_KIND_ID 120 121/// \brief A dynamically typed AST node container. 122/// 123/// Stores an AST node in a type safe way. This allows writing code that 124/// works with different kinds of AST nodes, despite the fact that they don't 125/// have a common base class. 126/// 127/// Use \c create(Node) to create a \c DynTypedNode from an AST node, 128/// and \c get<T>() to retrieve the node as type T if the types match. 129/// 130/// See \c NodeTypeTag for which node base types are currently supported; 131/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of 132/// the supported base types. 133class DynTypedNode { 134public: 135 /// \brief Creates a \c DynTypedNode from \c Node. 136 template <typename T> 137 static DynTypedNode create(const T &Node) { 138 return BaseConverter<T>::create(Node); 139 } 140 141 /// \brief Retrieve the stored node as type \c T. 142 /// 143 /// Returns NULL if the stored node does not have a type that is 144 /// convertible to \c T. 145 /// 146 /// For types that have identity via their pointer in the AST 147 /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned 148 /// pointer points to the referenced AST node. 149 /// For other types (like \c QualType) the value is stored directly 150 /// in the \c DynTypedNode, and the returned pointer points at 151 /// the storage inside DynTypedNode. For those nodes, do not 152 /// use the pointer outside the scope of the DynTypedNode. 153 template <typename T> 154 const T *get() const { 155 return BaseConverter<T>::get(NodeKind, Storage.buffer); 156 } 157 158 /// \brief Returns a pointer that identifies the stored AST node. 159 /// 160 /// Note that this is not supported by all AST nodes. For AST nodes 161 /// that don't have a pointer-defined identity inside the AST, this 162 /// method returns NULL. 163 const void *getMemoizationData() const; 164 165 /// @{ 166 /// \brief Imposes an order on \c DynTypedNode. 167 /// 168 /// Supports comparison of nodes that support memoization. 169 /// FIXME: Implement comparsion for other node types (currently 170 /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data). 171 bool operator<(const DynTypedNode &Other) const { 172 assert(getMemoizationData() && Other.getMemoizationData()); 173 return getMemoizationData() < Other.getMemoizationData(); 174 } 175 bool operator==(const DynTypedNode &Other) const { 176 // Nodes with different types cannot be equal. 177 if (!NodeKind.isSame(Other.NodeKind)) 178 return false; 179 180 // FIXME: Implement for other types. 181 if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) { 182 return *get<QualType>() == *Other.get<QualType>(); 183 } 184 assert(getMemoizationData() && Other.getMemoizationData()); 185 return getMemoizationData() == Other.getMemoizationData(); 186 } 187 bool operator!=(const DynTypedNode &Other) const { 188 return !operator==(Other); 189 } 190 /// @} 191 192private: 193 /// \brief Takes care of converting from and to \c T. 194 template <typename T, typename EnablerT = void> struct BaseConverter; 195 196 ASTNodeKind NodeKind; 197 198 /// \brief Stores the data of the node. 199 /// 200 /// Note that we can store \c Decls, \c Stmts, \c Types and 201 /// \c NestedNameSpecifiers by pointer as they are guaranteed to be unique 202 /// pointers pointing to dedicated storage in the AST. \c QualTypes on the 203 /// other hand do not have storage or unique pointers and thus need to be 204 /// stored by value. 205 llvm::AlignedCharArrayUnion<Decl *, Stmt *, Type *, NestedNameSpecifier *, 206 NestedNameSpecifierLoc, QualType, TypeLoc> 207 Storage; 208}; 209 210// FIXME: Pull out abstraction for the following. 211template<typename T> struct DynTypedNode::BaseConverter<T, 212 typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> { 213 static const T *get(ASTNodeKind NodeKind, const char Storage[]) { 214 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) 215 return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage)); 216 return NULL; 217 } 218 static DynTypedNode create(const Decl &Node) { 219 DynTypedNode Result; 220 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); 221 new (Result.Storage.buffer) const Decl*(&Node); 222 return Result; 223 } 224}; 225template<typename T> struct DynTypedNode::BaseConverter<T, 226 typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> { 227 static const T *get(ASTNodeKind NodeKind, const char Storage[]) { 228 if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) 229 return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage)); 230 return NULL; 231 } 232 static DynTypedNode create(const Stmt &Node) { 233 DynTypedNode Result; 234 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); 235 new (Result.Storage.buffer) const Stmt*(&Node); 236 return Result; 237 } 238}; 239template<typename T> struct DynTypedNode::BaseConverter<T, 240 typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> { 241 static const T *get(ASTNodeKind NodeKind, const char Storage[]) { 242 if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) 243 return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage)); 244 return NULL; 245 } 246 static DynTypedNode create(const Type &Node) { 247 DynTypedNode Result; 248 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); 249 new (Result.Storage.buffer) const Type*(&Node); 250 return Result; 251 } 252}; 253template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> { 254 static const NestedNameSpecifier *get(ASTNodeKind NodeKind, 255 const char Storage[]) { 256 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) 257 return *reinterpret_cast<NestedNameSpecifier*const*>(Storage); 258 return NULL; 259 } 260 static DynTypedNode create(const NestedNameSpecifier &Node) { 261 DynTypedNode Result; 262 Result.NodeKind = ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(); 263 new (Result.Storage.buffer) const NestedNameSpecifier*(&Node); 264 return Result; 265 } 266}; 267template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> { 268 static const NestedNameSpecifierLoc *get(ASTNodeKind NodeKind, 269 const char Storage[]) { 270 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isBaseOf( 271 NodeKind)) 272 return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage); 273 return NULL; 274 } 275 static DynTypedNode create(const NestedNameSpecifierLoc &Node) { 276 DynTypedNode Result; 277 Result.NodeKind = ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(); 278 new (Result.Storage.buffer) NestedNameSpecifierLoc(Node); 279 return Result; 280 } 281}; 282template<> struct DynTypedNode::BaseConverter<QualType, void> { 283 static const QualType *get(ASTNodeKind NodeKind, const char Storage[]) { 284 if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) 285 return reinterpret_cast<const QualType*>(Storage); 286 return NULL; 287 } 288 static DynTypedNode create(const QualType &Node) { 289 DynTypedNode Result; 290 Result.NodeKind = ASTNodeKind::getFromNodeKind<QualType>(); 291 new (Result.Storage.buffer) QualType(Node); 292 return Result; 293 } 294}; 295template<> struct DynTypedNode::BaseConverter<TypeLoc, void> { 296 static const TypeLoc *get(ASTNodeKind NodeKind, const char Storage[]) { 297 if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind)) 298 return reinterpret_cast<const TypeLoc*>(Storage); 299 return NULL; 300 } 301 static DynTypedNode create(const TypeLoc &Node) { 302 DynTypedNode Result; 303 Result.NodeKind = ASTNodeKind::getFromNodeKind<TypeLoc>(); 304 new (Result.Storage.buffer) TypeLoc(Node); 305 return Result; 306 } 307}; 308// The only operation we allow on unsupported types is \c get. 309// This allows to conveniently use \c DynTypedNode when having an arbitrary 310// AST node that is not supported, but prevents misuse - a user cannot create 311// a DynTypedNode from arbitrary types. 312template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { 313 static const T *get(ASTNodeKind NodeKind, const char Storage[]) { 314 return NULL; 315 } 316}; 317 318inline const void *DynTypedNode::getMemoizationData() const { 319 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(NodeKind)) { 320 return BaseConverter<Decl>::get(NodeKind, Storage.buffer); 321 } else if (ASTNodeKind::getFromNodeKind<Stmt>().isBaseOf(NodeKind)) { 322 return BaseConverter<Stmt>::get(NodeKind, Storage.buffer); 323 } else if (ASTNodeKind::getFromNodeKind<Type>().isBaseOf(NodeKind)) { 324 return BaseConverter<Type>::get(NodeKind, Storage.buffer); 325 } else if (ASTNodeKind::getFromNodeKind<NestedNameSpecifier>().isBaseOf(NodeKind)) { 326 return BaseConverter<NestedNameSpecifier>::get(NodeKind, Storage.buffer); 327 } 328 return NULL; 329} 330 331} // end namespace ast_type_traits 332} // end namespace clang 333 334#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H 335