1//===--- ASTMatchersTypeTraits.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_MATCHERS_AST_TYPE_TRAITS_H 16#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H 17 18#include "clang/AST/Decl.h" 19#include "clang/AST/Stmt.h" 20#include "llvm/Support/AlignOf.h" 21 22namespace clang { 23namespace ast_type_traits { 24 25/// \brief A dynamically typed AST node container. 26/// 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. 30/// 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. 33/// 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. 37class DynTypedNode { 38public: 39 /// \brief Creates a \c DynTypedNode from \c Node. 40 template <typename T> 41 static DynTypedNode create(const T &Node) { 42 return BaseConverter<T>::create(Node); 43 } 44 45 /// \brief Retrieve the stored node as type \c T. 46 /// 47 /// Returns NULL if the stored node does not have a type that is 48 /// convertible to \c T. 49 /// 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. 57 template <typename T> 58 const T *get() const { 59 return BaseConverter<T>::get(Tag, Storage.buffer); 60 } 61 62 /// \brief Returns a pointer that identifies the stored AST node. 63 /// 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; 68 69private: 70 /// \brief Takes care of converting from and to \c T. 71 template <typename T, typename EnablerT = void> struct BaseConverter; 72 73 /// \brief Supported base node types. 74 enum NodeTypeTag { 75 NT_Decl, 76 NT_Stmt, 77 NT_QualType 78 } Tag; 79 80 /// \brief Stores the data of the node. 81 /// 82 /// Note that we can store \c Decls and \c Stmts by pointer as they are 83 /// guaranteed to be unique pointers pointing to dedicated storage in the 84 /// AST. \c QualTypes on the other hand do not have storage or unique 85 /// pointers and thus need to be stored by value. 86 llvm::AlignedCharArrayUnion<Decl*, Stmt*, QualType> Storage; 87}; 88template<typename T> struct DynTypedNode::BaseConverter<T, 89 typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> { 90 static const T *get(NodeTypeTag Tag, const char Storage[]) { 91 if (Tag == NT_Decl) 92 return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage)); 93 return NULL; 94 } 95 static DynTypedNode create(const Decl &Node) { 96 DynTypedNode Result; 97 Result.Tag = NT_Decl; 98 new (Result.Storage.buffer) const Decl*(&Node); 99 return Result; 100 } 101}; 102template<typename T> struct DynTypedNode::BaseConverter<T, 103 typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> { 104 static const T *get(NodeTypeTag Tag, const char Storage[]) { 105 if (Tag == NT_Stmt) 106 return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage)); 107 return NULL; 108 } 109 static DynTypedNode create(const Stmt &Node) { 110 DynTypedNode Result; 111 Result.Tag = NT_Stmt; 112 new (Result.Storage.buffer) const Stmt*(&Node); 113 return Result; 114 } 115}; 116template<> struct DynTypedNode::BaseConverter<QualType, void> { 117 static const QualType *get(NodeTypeTag Tag, const char Storage[]) { 118 if (Tag == NT_QualType) 119 return reinterpret_cast<const QualType*>(Storage); 120 return NULL; 121 } 122 static DynTypedNode create(const QualType &Node) { 123 DynTypedNode Result; 124 Result.Tag = NT_QualType; 125 new (Result.Storage.buffer) QualType(Node); 126 return Result; 127 } 128}; 129// The only operation we allow on unsupported types is \c get. 130// This allows to conveniently use \c DynTypedNode when having an arbitrary 131// AST node that is not supported, but prevents misuse - a user cannot create 132// a DynTypedNode from arbitrary types. 133template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter { 134 static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; } 135}; 136 137inline const void *DynTypedNode::getMemoizationData() const { 138 switch (Tag) { 139 case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer); 140 case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer); 141 default: return NULL; 142 }; 143} 144 145} // end namespace ast_type_traits 146} // end namespace clang 147 148#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H 149 150