Home | History | Annotate | Download | only in AST
      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 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_AST_TYPE_TRAITS_H
     16 #define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
     17 
     18 #include "clang/AST/Decl.h"
     19 #include "clang/AST/Stmt.h"
     20 #include "clang/AST/TypeLoc.h"
     21 #include "llvm/Support/AlignOf.h"
     22 
     23 namespace clang {
     24 namespace ast_type_traits {
     25 
     26 /// \brief A dynamically typed AST node container.
     27 ///
     28 /// Stores an AST node in a type safe way. This allows writing code that
     29 /// works with different kinds of AST nodes, despite the fact that they don't
     30 /// have a common base class.
     31 ///
     32 /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
     33 /// and \c get<T>() to retrieve the node as type T if the types match.
     34 ///
     35 /// See \c NodeTypeTag for which node base types are currently supported;
     36 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
     37 /// the supported base types.
     38 class DynTypedNode {
     39 public:
     40   /// \brief Creates a \c DynTypedNode from \c Node.
     41   template <typename T>
     42   static DynTypedNode create(const T &Node) {
     43     return BaseConverter<T>::create(Node);
     44   }
     45 
     46   /// \brief Retrieve the stored node as type \c T.
     47   ///
     48   /// Returns NULL if the stored node does not have a type that is
     49   /// convertible to \c T.
     50   ///
     51   /// For types that have identity via their pointer in the AST
     52   /// (like \c Stmt and \c Decl) the returned pointer points to the
     53   /// referenced AST node.
     54   /// For other types (like \c QualType) the value is stored directly
     55   /// in the \c DynTypedNode, and the returned pointer points at
     56   /// the storage inside DynTypedNode. For those nodes, do not
     57   /// use the pointer outside the scope of the DynTypedNode.
     58   template <typename T>
     59   const T *get() const {
     60     return BaseConverter<T>::get(Tag, Storage.buffer);
     61   }
     62 
     63   /// \brief Returns a pointer that identifies the stored AST node.
     64   ///
     65   /// Note that this is not supported by all AST nodes. For AST nodes
     66   /// that don't have a pointer-defined identity inside the AST, this
     67   /// method returns NULL.
     68   const void *getMemoizationData() const;
     69 
     70 private:
     71   /// \brief Takes care of converting from and to \c T.
     72   template <typename T, typename EnablerT = void> struct BaseConverter;
     73 
     74   /// \brief Supported base node types.
     75   enum NodeTypeTag {
     76     NT_Decl,
     77     NT_Stmt,
     78     NT_NestedNameSpecifier,
     79     NT_NestedNameSpecifierLoc,
     80     NT_QualType,
     81     NT_Type,
     82     NT_TypeLoc
     83   } Tag;
     84 
     85   /// \brief Stores the data of the node.
     86   ///
     87   /// Note that we can store \c Decls and \c Stmts by pointer as they are
     88   /// guaranteed to be unique pointers pointing to dedicated storage in the
     89   /// AST. \c QualTypes on the other hand do not have storage or unique
     90   /// pointers and thus need to be stored by value.
     91   llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
     92                               NestedNameSpecifierLoc, QualType, Type,
     93                               TypeLoc> Storage;
     94 };
     95 
     96 // FIXME: Pull out abstraction for the following.
     97 template<typename T> struct DynTypedNode::BaseConverter<T,
     98     typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
     99   static const T *get(NodeTypeTag Tag, const char Storage[]) {
    100     if (Tag == NT_Decl)
    101       return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
    102     return NULL;
    103   }
    104   static DynTypedNode create(const Decl &Node) {
    105     DynTypedNode Result;
    106     Result.Tag = NT_Decl;
    107     new (Result.Storage.buffer) const Decl*(&Node);
    108     return Result;
    109   }
    110 };
    111 template<typename T> struct DynTypedNode::BaseConverter<T,
    112     typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
    113   static const T *get(NodeTypeTag Tag, const char Storage[]) {
    114     if (Tag == NT_Stmt)
    115       return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
    116     return NULL;
    117   }
    118   static DynTypedNode create(const Stmt &Node) {
    119     DynTypedNode Result;
    120     Result.Tag = NT_Stmt;
    121     new (Result.Storage.buffer) const Stmt*(&Node);
    122     return Result;
    123   }
    124 };
    125 template<typename T> struct DynTypedNode::BaseConverter<T,
    126     typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
    127   static const T *get(NodeTypeTag Tag, const char Storage[]) {
    128     if (Tag == NT_Type)
    129       return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
    130     return NULL;
    131   }
    132   static DynTypedNode create(const Type &Node) {
    133     DynTypedNode Result;
    134     Result.Tag = NT_Type;
    135     new (Result.Storage.buffer) const Type*(&Node);
    136     return Result;
    137   }
    138 };
    139 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
    140   static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
    141     if (Tag == NT_NestedNameSpecifier)
    142       return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
    143     return NULL;
    144   }
    145   static DynTypedNode create(const NestedNameSpecifier &Node) {
    146     DynTypedNode Result;
    147     Result.Tag = NT_NestedNameSpecifier;
    148     new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
    149     return Result;
    150   }
    151 };
    152 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
    153   static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
    154                                            const char Storage[]) {
    155     if (Tag == NT_NestedNameSpecifierLoc)
    156       return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
    157     return NULL;
    158   }
    159   static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
    160     DynTypedNode Result;
    161     Result.Tag = NT_NestedNameSpecifierLoc;
    162     new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
    163     return Result;
    164   }
    165 };
    166 template<> struct DynTypedNode::BaseConverter<QualType, void> {
    167   static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
    168     if (Tag == NT_QualType)
    169       return reinterpret_cast<const QualType*>(Storage);
    170     return NULL;
    171   }
    172   static DynTypedNode create(const QualType &Node) {
    173     DynTypedNode Result;
    174     Result.Tag = NT_QualType;
    175     new (Result.Storage.buffer) QualType(Node);
    176     return Result;
    177   }
    178 };
    179 template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
    180   static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
    181     if (Tag == NT_TypeLoc)
    182       return reinterpret_cast<const TypeLoc*>(Storage);
    183     return NULL;
    184   }
    185   static DynTypedNode create(const TypeLoc &Node) {
    186     DynTypedNode Result;
    187     Result.Tag = NT_TypeLoc;
    188     new (Result.Storage.buffer) TypeLoc(Node);
    189     return Result;
    190   }
    191 };
    192 // The only operation we allow on unsupported types is \c get.
    193 // This allows to conveniently use \c DynTypedNode when having an arbitrary
    194 // AST node that is not supported, but prevents misuse - a user cannot create
    195 // a DynTypedNode from arbitrary types.
    196 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
    197   static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
    198 };
    199 
    200 inline const void *DynTypedNode::getMemoizationData() const {
    201   switch (Tag) {
    202     case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
    203     case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
    204     default: return NULL;
    205   };
    206 }
    207 
    208 } // end namespace ast_type_traits
    209 } // end namespace clang
    210 
    211 #endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H
    212