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