//===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Provides a dynamically typed node container that can be used to store // an AST base node at runtime in the same storage in a type safe way. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" #include "clang/AST/TypeLoc.h" #include "llvm/Support/AlignOf.h" namespace clang { namespace ast_type_traits { /// \brief A dynamically typed AST node container. /// /// Stores an AST node in a type safe way. This allows writing code that /// works with different kinds of AST nodes, despite the fact that they don't /// have a common base class. /// /// Use \c create(Node) to create a \c DynTypedNode from an AST node, /// and \c get() to retrieve the node as type T if the types match. /// /// See \c NodeTypeTag for which node base types are currently supported; /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of /// the supported base types. class DynTypedNode { public: /// \brief Creates a \c DynTypedNode from \c Node. template static DynTypedNode create(const T &Node) { return BaseConverter::create(Node); } /// \brief Retrieve the stored node as type \c T. /// /// Returns NULL if the stored node does not have a type that is /// convertible to \c T. /// /// For types that have identity via their pointer in the AST /// (like \c Stmt and \c Decl) the returned pointer points to the /// referenced AST node. /// For other types (like \c QualType) the value is stored directly /// in the \c DynTypedNode, and the returned pointer points at /// the storage inside DynTypedNode. For those nodes, do not /// use the pointer outside the scope of the DynTypedNode. template const T *get() const { return BaseConverter::get(Tag, Storage.buffer); } /// \brief Returns a pointer that identifies the stored AST node. /// /// Note that this is not supported by all AST nodes. For AST nodes /// that don't have a pointer-defined identity inside the AST, this /// method returns NULL. const void *getMemoizationData() const; private: /// \brief Takes care of converting from and to \c T. template struct BaseConverter; /// \brief Supported base node types. enum NodeTypeTag { NT_Decl, NT_Stmt, NT_NestedNameSpecifier, NT_NestedNameSpecifierLoc, NT_QualType, NT_Type, NT_TypeLoc } Tag; /// \brief Stores the data of the node. /// /// Note that we can store \c Decls and \c Stmts by pointer as they are /// guaranteed to be unique pointers pointing to dedicated storage in the /// AST. \c QualTypes on the other hand do not have storage or unique /// pointers and thus need to be stored by value. llvm::AlignedCharArrayUnion Storage; }; // FIXME: Pull out abstraction for the following. template struct DynTypedNode::BaseConverter >::type> { static const T *get(NodeTypeTag Tag, const char Storage[]) { if (Tag == NT_Decl) return dyn_cast(*reinterpret_cast(Storage)); return NULL; } static DynTypedNode create(const Decl &Node) { DynTypedNode Result; Result.Tag = NT_Decl; new (Result.Storage.buffer) const Decl*(&Node); return Result; } }; template struct DynTypedNode::BaseConverter >::type> { static const T *get(NodeTypeTag Tag, const char Storage[]) { if (Tag == NT_Stmt) return dyn_cast(*reinterpret_cast(Storage)); return NULL; } static DynTypedNode create(const Stmt &Node) { DynTypedNode Result; Result.Tag = NT_Stmt; new (Result.Storage.buffer) const Stmt*(&Node); return Result; } }; template struct DynTypedNode::BaseConverter >::type> { static const T *get(NodeTypeTag Tag, const char Storage[]) { if (Tag == NT_Type) return dyn_cast(*reinterpret_cast(Storage)); return NULL; } static DynTypedNode create(const Type &Node) { DynTypedNode Result; Result.Tag = NT_Type; new (Result.Storage.buffer) const Type*(&Node); return Result; } }; template<> struct DynTypedNode::BaseConverter { static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) { if (Tag == NT_NestedNameSpecifier) return *reinterpret_cast(Storage); return NULL; } static DynTypedNode create(const NestedNameSpecifier &Node) { DynTypedNode Result; Result.Tag = NT_NestedNameSpecifier; new (Result.Storage.buffer) const NestedNameSpecifier*(&Node); return Result; } }; template<> struct DynTypedNode::BaseConverter { static const NestedNameSpecifierLoc *get(NodeTypeTag Tag, const char Storage[]) { if (Tag == NT_NestedNameSpecifierLoc) return reinterpret_cast(Storage); return NULL; } static DynTypedNode create(const NestedNameSpecifierLoc &Node) { DynTypedNode Result; Result.Tag = NT_NestedNameSpecifierLoc; new (Result.Storage.buffer) NestedNameSpecifierLoc(Node); return Result; } }; template<> struct DynTypedNode::BaseConverter { static const QualType *get(NodeTypeTag Tag, const char Storage[]) { if (Tag == NT_QualType) return reinterpret_cast(Storage); return NULL; } static DynTypedNode create(const QualType &Node) { DynTypedNode Result; Result.Tag = NT_QualType; new (Result.Storage.buffer) QualType(Node); return Result; } }; template<> struct DynTypedNode::BaseConverter { static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) { if (Tag == NT_TypeLoc) return reinterpret_cast(Storage); return NULL; } static DynTypedNode create(const TypeLoc &Node) { DynTypedNode Result; Result.Tag = NT_TypeLoc; new (Result.Storage.buffer) TypeLoc(Node); return Result; } }; // The only operation we allow on unsupported types is \c get. // This allows to conveniently use \c DynTypedNode when having an arbitrary // AST node that is not supported, but prevents misuse - a user cannot create // a DynTypedNode from arbitrary types. template struct DynTypedNode::BaseConverter { static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; } }; inline const void *DynTypedNode::getMemoizationData() const { switch (Tag) { case NT_Decl: return BaseConverter::get(Tag, Storage.buffer); case NT_Stmt: return BaseConverter::get(Tag, Storage.buffer); default: return NULL; }; } } // end namespace ast_type_traits } // end namespace clang #endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H