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