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