Home | History | Annotate | Line # | Download | only in AST
      1 //===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 //  Provides a dynamic type identifier and a dynamically typed node container
     10 //  that can be used to store an AST base node at runtime in the same storage in
     11 //  a type safe way.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_CLANG_AST_ASTTYPETRAITS_H
     16 #define LLVM_CLANG_AST_ASTTYPETRAITS_H
     17 
     18 #include "clang/AST/ASTFwd.h"
     19 #include "clang/AST/DeclCXX.h"
     20 #include "clang/AST/NestedNameSpecifier.h"
     21 #include "clang/AST/TemplateBase.h"
     22 #include "clang/AST/TypeLoc.h"
     23 #include "clang/Basic/LLVM.h"
     24 #include "llvm/ADT/DenseMapInfo.h"
     25 #include "llvm/Support/AlignOf.h"
     26 
     27 namespace llvm {
     28 
     29 class raw_ostream;
     30 
     31 }
     32 
     33 namespace clang {
     34 
     35 struct PrintingPolicy;
     36 
     37 /// Defines how we descend a level in the AST when we pass
     38 /// through expressions.
     39 enum TraversalKind {
     40   /// Will traverse all child nodes.
     41   TK_AsIs,
     42 
     43   /// Ignore AST nodes not written in the source
     44   TK_IgnoreUnlessSpelledInSource
     45 };
     46 
     47 /// Kind identifier.
     48 ///
     49 /// It can be constructed from any node kind and allows for runtime type
     50 /// hierarchy checks.
     51 /// Use getFromNodeKind<T>() to construct them.
     52 class ASTNodeKind {
     53 public:
     54   /// Empty identifier. It matches nothing.
     55   ASTNodeKind() : KindId(NKI_None) {}
     56 
     57   /// Construct an identifier for T.
     58   template <class T>
     59   static ASTNodeKind getFromNodeKind() {
     60     return ASTNodeKind(KindToKindId<T>::Id);
     61   }
     62 
     63   /// \{
     64   /// Construct an identifier for the dynamic type of the node
     65   static ASTNodeKind getFromNode(const Decl &D);
     66   static ASTNodeKind getFromNode(const Stmt &S);
     67   static ASTNodeKind getFromNode(const Type &T);
     68   static ASTNodeKind getFromNode(const OMPClause &C);
     69   /// \}
     70 
     71   /// Returns \c true if \c this and \c Other represent the same kind.
     72   bool isSame(ASTNodeKind Other) const {
     73     return KindId != NKI_None && KindId == Other.KindId;
     74   }
     75 
     76   /// Returns \c true only for the default \c ASTNodeKind()
     77   bool isNone() const { return KindId == NKI_None; }
     78 
     79   /// Returns \c true if \c this is a base kind of (or same as) \c Other.
     80   /// \param Distance If non-null, used to return the distance between \c this
     81   /// and \c Other in the class hierarchy.
     82   bool isBaseOf(ASTNodeKind Other, unsigned *Distance = nullptr) const;
     83 
     84   /// String representation of the kind.
     85   StringRef asStringRef() const;
     86 
     87   /// Strict weak ordering for ASTNodeKind.
     88   bool operator<(const ASTNodeKind &Other) const {
     89     return KindId < Other.KindId;
     90   }
     91 
     92   /// Return the most derived type between \p Kind1 and \p Kind2.
     93   ///
     94   /// Return ASTNodeKind() if they are not related.
     95   static ASTNodeKind getMostDerivedType(ASTNodeKind Kind1, ASTNodeKind Kind2);
     96 
     97   /// Return the most derived common ancestor between Kind1 and Kind2.
     98   ///
     99   /// Return ASTNodeKind() if they are not related.
    100   static ASTNodeKind getMostDerivedCommonAncestor(ASTNodeKind Kind1,
    101                                                   ASTNodeKind Kind2);
    102 
    103   ASTNodeKind getCladeKind() const;
    104 
    105   /// Hooks for using ASTNodeKind as a key in a DenseMap.
    106   struct DenseMapInfo {
    107     // ASTNodeKind() is a good empty key because it is represented as a 0.
    108     static inline ASTNodeKind getEmptyKey() { return ASTNodeKind(); }
    109     // NKI_NumberOfKinds is not a valid value, so it is good for a
    110     // tombstone key.
    111     static inline ASTNodeKind getTombstoneKey() {
    112       return ASTNodeKind(NKI_NumberOfKinds);
    113     }
    114     static unsigned getHashValue(const ASTNodeKind &Val) { return Val.KindId; }
    115     static bool isEqual(const ASTNodeKind &LHS, const ASTNodeKind &RHS) {
    116       return LHS.KindId == RHS.KindId;
    117     }
    118   };
    119 
    120   /// Check if the given ASTNodeKind identifies a type that offers pointer
    121   /// identity. This is useful for the fast path in DynTypedNode.
    122   bool hasPointerIdentity() const {
    123     return KindId > NKI_LastKindWithoutPointerIdentity;
    124   }
    125 
    126 private:
    127   /// Kind ids.
    128   ///
    129   /// Includes all possible base and derived kinds.
    130   enum NodeKindId {
    131     NKI_None,
    132     NKI_TemplateArgument,
    133     NKI_TemplateArgumentLoc,
    134     NKI_TemplateName,
    135     NKI_NestedNameSpecifierLoc,
    136     NKI_QualType,
    137     NKI_TypeLoc,
    138     NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc,
    139     NKI_CXXBaseSpecifier,
    140     NKI_CXXCtorInitializer,
    141     NKI_NestedNameSpecifier,
    142     NKI_Decl,
    143 #define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
    144 #include "clang/AST/DeclNodes.inc"
    145     NKI_Stmt,
    146 #define STMT(DERIVED, BASE) NKI_##DERIVED,
    147 #include "clang/AST/StmtNodes.inc"
    148     NKI_Type,
    149 #define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
    150 #include "clang/AST/TypeNodes.inc"
    151     NKI_OMPClause,
    152 #define GEN_CLANG_CLAUSE_CLASS
    153 #define CLAUSE_CLASS(Enum, Str, Class) NKI_##Class,
    154 #include "llvm/Frontend/OpenMP/OMP.inc"
    155     NKI_NumberOfKinds
    156   };
    157 
    158   /// Use getFromNodeKind<T>() to construct the kind.
    159   ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
    160 
    161   /// Returns \c true if \c Base is a base kind of (or same as) \c
    162   ///   Derived.
    163   /// \param Distance If non-null, used to return the distance between \c Base
    164   /// and \c Derived in the class hierarchy.
    165   static bool isBaseOf(NodeKindId Base, NodeKindId Derived, unsigned *Distance);
    166 
    167   /// Helper meta-function to convert a kind T to its enum value.
    168   ///
    169   /// This struct is specialized below for all known kinds.
    170   template <class T> struct KindToKindId {
    171     static const NodeKindId Id = NKI_None;
    172   };
    173   template <class T>
    174   struct KindToKindId<const T> : KindToKindId<T> {};
    175 
    176   /// Per kind info.
    177   struct KindInfo {
    178     /// The id of the parent kind, or None if it has no parent.
    179     NodeKindId ParentId;
    180     /// Name of the kind.
    181     const char *Name;
    182   };
    183   static const KindInfo AllKindInfo[NKI_NumberOfKinds];
    184 
    185   NodeKindId KindId;
    186 };
    187 
    188 #define KIND_TO_KIND_ID(Class)                                                 \
    189   template <> struct ASTNodeKind::KindToKindId<Class> {                        \
    190     static const NodeKindId Id = NKI_##Class;                                  \
    191   };
    192 KIND_TO_KIND_ID(CXXCtorInitializer)
    193 KIND_TO_KIND_ID(TemplateArgument)
    194 KIND_TO_KIND_ID(TemplateArgumentLoc)
    195 KIND_TO_KIND_ID(TemplateName)
    196 KIND_TO_KIND_ID(NestedNameSpecifier)
    197 KIND_TO_KIND_ID(NestedNameSpecifierLoc)
    198 KIND_TO_KIND_ID(QualType)
    199 KIND_TO_KIND_ID(TypeLoc)
    200 KIND_TO_KIND_ID(Decl)
    201 KIND_TO_KIND_ID(Stmt)
    202 KIND_TO_KIND_ID(Type)
    203 KIND_TO_KIND_ID(OMPClause)
    204 KIND_TO_KIND_ID(CXXBaseSpecifier)
    205 #define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
    206 #include "clang/AST/DeclNodes.inc"
    207 #define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
    208 #include "clang/AST/StmtNodes.inc"
    209 #define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
    210 #include "clang/AST/TypeNodes.inc"
    211 #define GEN_CLANG_CLAUSE_CLASS
    212 #define CLAUSE_CLASS(Enum, Str, Class) KIND_TO_KIND_ID(Class)
    213 #include "llvm/Frontend/OpenMP/OMP.inc"
    214 #undef KIND_TO_KIND_ID
    215 
    216 inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) {
    217   OS << K.asStringRef();
    218   return OS;
    219 }
    220 
    221 /// A dynamically typed AST node container.
    222 ///
    223 /// Stores an AST node in a type safe way. This allows writing code that
    224 /// works with different kinds of AST nodes, despite the fact that they don't
    225 /// have a common base class.
    226 ///
    227 /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
    228 /// and \c get<T>() to retrieve the node as type T if the types match.
    229 ///
    230 /// See \c ASTNodeKind for which node base types are currently supported;
    231 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
    232 /// the supported base types.
    233 class DynTypedNode {
    234 public:
    235   /// Creates a \c DynTypedNode from \c Node.
    236   template <typename T>
    237   static DynTypedNode create(const T &Node) {
    238     return BaseConverter<T>::create(Node);
    239   }
    240 
    241   /// Retrieve the stored node as type \c T.
    242   ///
    243   /// Returns NULL if the stored node does not have a type that is
    244   /// convertible to \c T.
    245   ///
    246   /// For types that have identity via their pointer in the AST
    247   /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
    248   /// pointer points to the referenced AST node.
    249   /// For other types (like \c QualType) the value is stored directly
    250   /// in the \c DynTypedNode, and the returned pointer points at
    251   /// the storage inside DynTypedNode. For those nodes, do not
    252   /// use the pointer outside the scope of the DynTypedNode.
    253   template <typename T> const T *get() const {
    254     return BaseConverter<T>::get(NodeKind, &Storage);
    255   }
    256 
    257   /// Retrieve the stored node as type \c T.
    258   ///
    259   /// Similar to \c get(), but asserts that the type is what we are expecting.
    260   template <typename T>
    261   const T &getUnchecked() const {
    262     return BaseConverter<T>::getUnchecked(NodeKind, &Storage);
    263   }
    264 
    265   ASTNodeKind getNodeKind() const { return NodeKind; }
    266 
    267   /// Returns a pointer that identifies the stored AST node.
    268   ///
    269   /// Note that this is not supported by all AST nodes. For AST nodes
    270   /// that don't have a pointer-defined identity inside the AST, this
    271   /// method returns NULL.
    272   const void *getMemoizationData() const {
    273     return NodeKind.hasPointerIdentity()
    274                ? *reinterpret_cast<void *const *>(&Storage)
    275                : nullptr;
    276   }
    277 
    278   /// Prints the node to the given output stream.
    279   void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
    280 
    281   /// Dumps the node to the given output stream.
    282   void dump(llvm::raw_ostream &OS, const ASTContext &Context) const;
    283 
    284   /// For nodes which represent textual entities in the source code,
    285   /// return their SourceRange.  For all other nodes, return SourceRange().
    286   SourceRange getSourceRange() const;
    287 
    288   /// @{
    289   /// Imposes an order on \c DynTypedNode.
    290   ///
    291   /// Supports comparison of nodes that support memoization.
    292   /// FIXME: Implement comparison for other node types (currently
    293   /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
    294   bool operator<(const DynTypedNode &Other) const {
    295     if (!NodeKind.isSame(Other.NodeKind))
    296       return NodeKind < Other.NodeKind;
    297 
    298     if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
    299       return getUnchecked<QualType>().getAsOpaquePtr() <
    300              Other.getUnchecked<QualType>().getAsOpaquePtr();
    301 
    302     if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) {
    303       auto TLA = getUnchecked<TypeLoc>();
    304       auto TLB = Other.getUnchecked<TypeLoc>();
    305       return std::make_pair(TLA.getType().getAsOpaquePtr(),
    306                             TLA.getOpaqueData()) <
    307              std::make_pair(TLB.getType().getAsOpaquePtr(),
    308                             TLB.getOpaqueData());
    309     }
    310 
    311     if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
    312             NodeKind)) {
    313       auto NNSLA = getUnchecked<NestedNameSpecifierLoc>();
    314       auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>();
    315       return std::make_pair(NNSLA.getNestedNameSpecifier(),
    316                             NNSLA.getOpaqueData()) <
    317              std::make_pair(NNSLB.getNestedNameSpecifier(),
    318                             NNSLB.getOpaqueData());
    319     }
    320 
    321     assert(getMemoizationData() && Other.getMemoizationData());
    322     return getMemoizationData() < Other.getMemoizationData();
    323   }
    324   bool operator==(const DynTypedNode &Other) const {
    325     // DynTypedNode::create() stores the exact kind of the node in NodeKind.
    326     // If they contain the same node, their NodeKind must be the same.
    327     if (!NodeKind.isSame(Other.NodeKind))
    328       return false;
    329 
    330     // FIXME: Implement for other types.
    331     if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
    332       return getUnchecked<QualType>() == Other.getUnchecked<QualType>();
    333 
    334     if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind))
    335       return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>();
    336 
    337     if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(NodeKind))
    338       return getUnchecked<NestedNameSpecifierLoc>() ==
    339              Other.getUnchecked<NestedNameSpecifierLoc>();
    340 
    341     assert(getMemoizationData() && Other.getMemoizationData());
    342     return getMemoizationData() == Other.getMemoizationData();
    343   }
    344   bool operator!=(const DynTypedNode &Other) const {
    345     return !operator==(Other);
    346   }
    347   /// @}
    348 
    349   /// Hooks for using DynTypedNode as a key in a DenseMap.
    350   struct DenseMapInfo {
    351     static inline DynTypedNode getEmptyKey() {
    352       DynTypedNode Node;
    353       Node.NodeKind = ASTNodeKind::DenseMapInfo::getEmptyKey();
    354       return Node;
    355     }
    356     static inline DynTypedNode getTombstoneKey() {
    357       DynTypedNode Node;
    358       Node.NodeKind = ASTNodeKind::DenseMapInfo::getTombstoneKey();
    359       return Node;
    360     }
    361     static unsigned getHashValue(const DynTypedNode &Val) {
    362       // FIXME: Add hashing support for the remaining types.
    363       if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(Val.NodeKind)) {
    364         auto TL = Val.getUnchecked<TypeLoc>();
    365         return llvm::hash_combine(TL.getType().getAsOpaquePtr(),
    366                                   TL.getOpaqueData());
    367       }
    368 
    369       if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
    370               Val.NodeKind)) {
    371         auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>();
    372         return llvm::hash_combine(NNSL.getNestedNameSpecifier(),
    373                                   NNSL.getOpaqueData());
    374       }
    375 
    376       assert(Val.getMemoizationData());
    377       return llvm::hash_value(Val.getMemoizationData());
    378     }
    379     static bool isEqual(const DynTypedNode &LHS, const DynTypedNode &RHS) {
    380       auto Empty = ASTNodeKind::DenseMapInfo::getEmptyKey();
    381       auto TombStone = ASTNodeKind::DenseMapInfo::getTombstoneKey();
    382       return (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, Empty) &&
    383               ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, Empty)) ||
    384              (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, TombStone) &&
    385               ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, TombStone)) ||
    386              LHS == RHS;
    387     }
    388   };
    389 
    390 private:
    391   /// Takes care of converting from and to \c T.
    392   template <typename T, typename EnablerT = void> struct BaseConverter;
    393 
    394   /// Converter that uses dyn_cast<T> from a stored BaseT*.
    395   template <typename T, typename BaseT> struct DynCastPtrConverter {
    396     static const T *get(ASTNodeKind NodeKind, const void *Storage) {
    397       if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))
    398         return &getUnchecked(NodeKind, Storage);
    399       return nullptr;
    400     }
    401     static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
    402       assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind));
    403       return *cast<T>(static_cast<const BaseT *>(
    404           *reinterpret_cast<const void *const *>(Storage)));
    405     }
    406     static DynTypedNode create(const BaseT &Node) {
    407       DynTypedNode Result;
    408       Result.NodeKind = ASTNodeKind::getFromNode(Node);
    409       new (&Result.Storage) const void *(&Node);
    410       return Result;
    411     }
    412   };
    413 
    414   /// Converter that stores T* (by pointer).
    415   template <typename T> struct PtrConverter {
    416     static const T *get(ASTNodeKind NodeKind, const void *Storage) {
    417       if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
    418         return &getUnchecked(NodeKind, Storage);
    419       return nullptr;
    420     }
    421     static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
    422       assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind));
    423       return *static_cast<const T *>(
    424           *reinterpret_cast<const void *const *>(Storage));
    425     }
    426     static DynTypedNode create(const T &Node) {
    427       DynTypedNode Result;
    428       Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
    429       new (&Result.Storage) const void *(&Node);
    430       return Result;
    431     }
    432   };
    433 
    434   /// Converter that stores T (by value).
    435   template <typename T> struct ValueConverter {
    436     static const T *get(ASTNodeKind NodeKind, const void *Storage) {
    437       if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
    438         return reinterpret_cast<const T *>(Storage);
    439       return nullptr;
    440     }
    441     static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
    442       assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind));
    443       return *reinterpret_cast<const T *>(Storage);
    444     }
    445     static DynTypedNode create(const T &Node) {
    446       DynTypedNode Result;
    447       Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
    448       new (&Result.Storage) T(Node);
    449       return Result;
    450     }
    451   };
    452 
    453   ASTNodeKind NodeKind;
    454 
    455   /// Stores the data of the node.
    456   ///
    457   /// Note that we can store \c Decls, \c Stmts, \c Types,
    458   /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
    459   /// guaranteed to be unique pointers pointing to dedicated storage in the AST.
    460   /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs,
    461   /// \c TemplateArguments and \c TemplateArgumentLocs on the other hand do not
    462   /// have storage or unique pointers and thus need to be stored by value.
    463   llvm::AlignedCharArrayUnion<const void *, TemplateArgument,
    464                               TemplateArgumentLoc, NestedNameSpecifierLoc,
    465                               QualType, TypeLoc>
    466       Storage;
    467 };
    468 
    469 template <typename T>
    470 struct DynTypedNode::BaseConverter<
    471     T, std::enable_if_t<std::is_base_of<Decl, T>::value>>
    472     : public DynCastPtrConverter<T, Decl> {};
    473 
    474 template <typename T>
    475 struct DynTypedNode::BaseConverter<
    476     T, std::enable_if_t<std::is_base_of<Stmt, T>::value>>
    477     : public DynCastPtrConverter<T, Stmt> {};
    478 
    479 template <typename T>
    480 struct DynTypedNode::BaseConverter<
    481     T, std::enable_if_t<std::is_base_of<Type, T>::value>>
    482     : public DynCastPtrConverter<T, Type> {};
    483 
    484 template <typename T>
    485 struct DynTypedNode::BaseConverter<
    486     T, std::enable_if_t<std::is_base_of<OMPClause, T>::value>>
    487     : public DynCastPtrConverter<T, OMPClause> {};
    488 
    489 template <>
    490 struct DynTypedNode::BaseConverter<
    491     NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
    492 
    493 template <>
    494 struct DynTypedNode::BaseConverter<
    495     CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
    496 
    497 template <>
    498 struct DynTypedNode::BaseConverter<
    499     TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
    500 
    501 template <>
    502 struct DynTypedNode::BaseConverter<TemplateArgumentLoc, void>
    503     : public ValueConverter<TemplateArgumentLoc> {};
    504 
    505 template <>
    506 struct DynTypedNode::BaseConverter<
    507     TemplateName, void> : public ValueConverter<TemplateName> {};
    508 
    509 template <>
    510 struct DynTypedNode::BaseConverter<
    511     NestedNameSpecifierLoc,
    512     void> : public ValueConverter<NestedNameSpecifierLoc> {};
    513 
    514 template <>
    515 struct DynTypedNode::BaseConverter<QualType,
    516                                    void> : public ValueConverter<QualType> {};
    517 
    518 template <>
    519 struct DynTypedNode::BaseConverter<
    520     TypeLoc, void> : public ValueConverter<TypeLoc> {};
    521 
    522 template <>
    523 struct DynTypedNode::BaseConverter<CXXBaseSpecifier, void>
    524     : public PtrConverter<CXXBaseSpecifier> {};
    525 
    526 // The only operation we allow on unsupported types is \c get.
    527 // This allows to conveniently use \c DynTypedNode when having an arbitrary
    528 // AST node that is not supported, but prevents misuse - a user cannot create
    529 // a DynTypedNode from arbitrary types.
    530 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
    531   static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
    532     return NULL;
    533   }
    534 };
    535 
    536 } // end namespace clang
    537 
    538 namespace llvm {
    539 
    540 template <>
    541 struct DenseMapInfo<clang::ASTNodeKind> : clang::ASTNodeKind::DenseMapInfo {};
    542 
    543 template <>
    544 struct DenseMapInfo<clang::DynTypedNode> : clang::DynTypedNode::DenseMapInfo {};
    545 
    546 }  // end namespace llvm
    547 
    548 #endif
    549