ASTTypeTraits.h revision 263508
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 28namespace llvm { 29 30class raw_ostream; 31 32} 33 34namespace clang { 35 36struct PrintingPolicy; 37 38namespace ast_type_traits { 39 40/// \brief Kind identifier. 41/// 42/// It can be constructed from any node kind and allows for runtime type 43/// hierarchy checks. 44/// Use getFromNodeKind<T>() to construct them. 45class ASTNodeKind { 46public: 47 /// \brief Empty identifier. It matches nothing. 48 ASTNodeKind() : KindId(NKI_None) {} 49 50 /// \brief Construct an identifier for T. 51 template <class T> 52 static ASTNodeKind getFromNodeKind() { 53 return ASTNodeKind(KindToKindId<T>::Id); 54 } 55 56 /// \brief Returns \c true if \c this and \c Other represent the same kind. 57 bool isSame(ASTNodeKind Other) const; 58 59 /// \brief Returns \c true if \c this is a base kind of (or same as) \c Other. 60 bool isBaseOf(ASTNodeKind Other) const; 61 62 /// \brief String representation of the kind. 63 StringRef asStringRef() const; 64 65private: 66 /// \brief Kind ids. 67 /// 68 /// Includes all possible base and derived kinds. 69 enum NodeKindId { 70 NKI_None, 71 NKI_CXXCtorInitializer, 72 NKI_TemplateArgument, 73 NKI_NestedNameSpecifier, 74 NKI_NestedNameSpecifierLoc, 75 NKI_QualType, 76 NKI_TypeLoc, 77 NKI_Decl, 78#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl, 79#include "clang/AST/DeclNodes.inc" 80 NKI_Stmt, 81#define STMT(DERIVED, BASE) NKI_##DERIVED, 82#include "clang/AST/StmtNodes.inc" 83 NKI_Type, 84#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type, 85#include "clang/AST/TypeNodes.def" 86 NKI_NumberOfKinds 87 }; 88 89 /// \brief Use getFromNodeKind<T>() to construct the kind. 90 ASTNodeKind(NodeKindId KindId) : KindId(KindId) {} 91 92 /// \brief Returns \c true if \c Base is a base kind of (or same as) \c 93 /// Derived. 94 static bool isBaseOf(NodeKindId Base, NodeKindId Derived); 95 96 /// \brief Helper meta-function to convert a kind T to its enum value. 97 /// 98 /// This struct is specialized below for all known kinds. 99 template <class T> struct KindToKindId { 100 static const NodeKindId Id = NKI_None; 101 }; 102 103 /// \brief Per kind info. 104 struct KindInfo { 105 /// \brief The id of the parent kind, or None if it has no parent. 106 NodeKindId ParentId; 107 /// \brief Name of the kind. 108 const char *Name; 109 }; 110 static const KindInfo AllKindInfo[NKI_NumberOfKinds]; 111 112 NodeKindId KindId; 113}; 114 115#define KIND_TO_KIND_ID(Class) \ 116 template <> struct ASTNodeKind::KindToKindId<Class> { \ 117 static const NodeKindId Id = NKI_##Class; \ 118 }; 119KIND_TO_KIND_ID(CXXCtorInitializer) 120KIND_TO_KIND_ID(TemplateArgument) 121KIND_TO_KIND_ID(NestedNameSpecifier) 122KIND_TO_KIND_ID(NestedNameSpecifierLoc) 123KIND_TO_KIND_ID(QualType) 124KIND_TO_KIND_ID(TypeLoc) 125KIND_TO_KIND_ID(Decl) 126KIND_TO_KIND_ID(Stmt) 127KIND_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 135 136/// \brief A dynamically typed AST node container. 137/// 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. 141/// 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. 144/// 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. 148class DynTypedNode { 149public: 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); 154 } 155 156 /// \brief Retrieve the stored node as type \c T. 157 /// 158 /// Returns NULL if the stored node does not have a type that is 159 /// convertible to \c T. 160 /// 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); 171 } 172 173 /// \brief Returns a pointer that identifies the stored AST node. 174 /// 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; 179 180 /// \brief Prints the node to the given output stream. 181 void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const; 182 183 /// \brief Dumps the node to the given output stream. 184 void dump(llvm::raw_ostream &OS, SourceManager &SM) const; 185 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; 189 190 /// @{ 191 /// \brief Imposes an order on \c DynTypedNode. 192 /// 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(); 199 } 200 bool operator==(const DynTypedNode &Other) const { 201 // Nodes with different types cannot be equal. 202 if (!NodeKind.isSame(Other.NodeKind)) 203 return false; 204 205 // FIXME: Implement for other types. 206 if (ASTNodeKind::getFromNodeKind<QualType>().isBaseOf(NodeKind)) { 207 return *get<QualType>() == *Other.get<QualType>(); 208 } 209 assert(getMemoizationData() && Other.getMemoizationData()); 210 return getMemoizationData() == Other.getMemoizationData(); 211 } 212 bool operator!=(const DynTypedNode &Other) const { 213 return !operator==(Other); 214 } 215 /// @} 216 217private: 218 /// \brief Takes care of converting from and to \c T. 219 template <typename T, typename EnablerT = void> struct BaseConverter; 220 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)); 226 return NULL; 227 } 228 static DynTypedNode create(const BaseT &Node) { 229 DynTypedNode Result; 230 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); 231 new (Result.Storage.buffer) const BaseT * (&Node); 232 return Result; 233 } 234 }; 235 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); 241 return NULL; 242 } 243 static DynTypedNode create(const T &Node) { 244 DynTypedNode Result; 245 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); 246 new (Result.Storage.buffer) const T * (&Node); 247 return Result; 248 } 249 }; 250 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); 256 return NULL; 257 } 258 static DynTypedNode create(const T &Node) { 259 DynTypedNode Result; 260 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>(); 261 new (Result.Storage.buffer) T(Node); 262 return Result; 263 } 264 }; 265 266 ASTNodeKind NodeKind; 267 268 /// \brief Stores the data of the node. 269 /// 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 *> 278 KindsByPointer; 279 llvm::AlignedCharArrayUnion<KindsByPointer, TemplateArgument, 280 NestedNameSpecifierLoc, QualType, TypeLoc> 281 Storage; 282}; 283 284template <typename T> 285struct DynTypedNode::BaseConverter< 286 T, typename llvm::enable_if<llvm::is_base_of< 287 Decl, T> >::type> : public DynCastPtrConverter<T, Decl> {}; 288 289template <typename T> 290struct DynTypedNode::BaseConverter< 291 T, typename llvm::enable_if<llvm::is_base_of< 292 Stmt, T> >::type> : public DynCastPtrConverter<T, Stmt> {}; 293 294template <typename T> 295struct DynTypedNode::BaseConverter< 296 T, typename llvm::enable_if<llvm::is_base_of< 297 Type, T> >::type> : public DynCastPtrConverter<T, Type> {}; 298 299template <> 300struct DynTypedNode::BaseConverter< 301 NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {}; 302 303template <> 304struct DynTypedNode::BaseConverter< 305 CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {}; 306 307template <> 308struct DynTypedNode::BaseConverter< 309 TemplateArgument, void> : public ValueConverter<TemplateArgument> {}; 310 311template <> 312struct DynTypedNode::BaseConverter< 313 NestedNameSpecifierLoc, 314 void> : public ValueConverter<NestedNameSpecifierLoc> {}; 315 316template <> 317struct DynTypedNode::BaseConverter<QualType, 318 void> : public ValueConverter<QualType> {}; 319 320template <> 321struct DynTypedNode::BaseConverter< 322 TypeLoc, void> : public ValueConverter<TypeLoc> {}; 323 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. 328template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { 329 static const T *get(ASTNodeKind NodeKind, const char Storage[]) { 330 return NULL; 331 } 332}; 333 334inline 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); 343 } 344 return NULL; 345} 346 347} // end namespace ast_type_traits 348} // end namespace clang 349 350#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H 351