1 //===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_AST_ASTTYPETRAITS_H
16 #define LLVM_CLANG_AST_ASTTYPETRAITS_H
18 #include "clang/AST/ASTFwd.h"
19 #include "clang/AST/Decl.h"
20 #include "clang/AST/NestedNameSpecifier.h"
21 #include "clang/AST/OpenMPClause.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/ADT/DenseMapInfo.h"
27 #include "llvm/Support/AlignOf.h"
37 struct PrintingPolicy;
39 namespace ast_type_traits {
41 /// Defines how we descend a level in the AST when we pass
42 /// through expressions.
44 /// Will traverse all child nodes.
47 /// Will not traverse implicit casts and parentheses.
48 /// Corresponds to Expr::IgnoreParenImpCasts()
49 TK_IgnoreImplicitCastsAndParentheses
54 /// It can be constructed from any node kind and allows for runtime type
56 /// Use getFromNodeKind<T>() to construct them.
59 /// Empty identifier. It matches nothing.
60 ASTNodeKind() : KindId(NKI_None) {}
62 /// Construct an identifier for T.
64 static ASTNodeKind getFromNodeKind() {
65 return ASTNodeKind(KindToKindId<T>::Id);
69 /// Construct an identifier for the dynamic type of the node
70 static ASTNodeKind getFromNode(const Decl &D);
71 static ASTNodeKind getFromNode(const Stmt &S);
72 static ASTNodeKind getFromNode(const Type &T);
73 static ASTNodeKind getFromNode(const OMPClause &C);
76 /// Returns \c true if \c this and \c Other represent the same kind.
77 bool isSame(ASTNodeKind Other) const {
78 return KindId != NKI_None && KindId == Other.KindId;
81 /// Returns \c true only for the default \c ASTNodeKind()
82 bool isNone() const { return KindId == NKI_None; }
84 /// Returns \c true if \c this is a base kind of (or same as) \c Other.
85 /// \param Distance If non-null, used to return the distance between \c this
86 /// and \c Other in the class hierarchy.
87 bool isBaseOf(ASTNodeKind Other, unsigned *Distance = nullptr) const;
89 /// String representation of the kind.
90 StringRef asStringRef() const;
92 /// Strict weak ordering for ASTNodeKind.
93 bool operator<(const ASTNodeKind &Other) const {
94 return KindId < Other.KindId;
97 /// Return the most derived type between \p Kind1 and \p Kind2.
99 /// Return ASTNodeKind() if they are not related.
100 static ASTNodeKind getMostDerivedType(ASTNodeKind Kind1, ASTNodeKind Kind2);
102 /// Return the most derived common ancestor between Kind1 and Kind2.
104 /// Return ASTNodeKind() if they are not related.
105 static ASTNodeKind getMostDerivedCommonAncestor(ASTNodeKind Kind1,
108 /// Hooks for using ASTNodeKind as a key in a DenseMap.
109 struct DenseMapInfo {
110 // ASTNodeKind() is a good empty key because it is represented as a 0.
111 static inline ASTNodeKind getEmptyKey() { return ASTNodeKind(); }
112 // NKI_NumberOfKinds is not a valid value, so it is good for a
114 static inline ASTNodeKind getTombstoneKey() {
115 return ASTNodeKind(NKI_NumberOfKinds);
117 static unsigned getHashValue(const ASTNodeKind &Val) { return Val.KindId; }
118 static bool isEqual(const ASTNodeKind &LHS, const ASTNodeKind &RHS) {
119 return LHS.KindId == RHS.KindId;
123 /// Check if the given ASTNodeKind identifies a type that offers pointer
124 /// identity. This is useful for the fast path in DynTypedNode.
125 bool hasPointerIdentity() const {
126 return KindId > NKI_LastKindWithoutPointerIdentity;
132 /// Includes all possible base and derived kinds.
135 NKI_TemplateArgument,
137 NKI_NestedNameSpecifierLoc,
140 NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc,
141 NKI_CXXCtorInitializer,
142 NKI_NestedNameSpecifier,
144 #define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
145 #include "clang/AST/DeclNodes.inc"
147 #define STMT(DERIVED, BASE) NKI_##DERIVED,
148 #include "clang/AST/StmtNodes.inc"
150 #define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
151 #include "clang/AST/TypeNodes.def"
153 #define OPENMP_CLAUSE(TextualSpelling, Class) NKI_##Class,
154 #include "clang/Basic/OpenMPKinds.def"
158 /// Use getFromNodeKind<T>() to construct the kind.
159 ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
161 /// Returns \c true if \c Base is a base kind of (or same as) \c
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);
167 /// Helper meta-function to convert a kind T to its enum value.
169 /// This struct is specialized below for all known kinds.
170 template <class T> struct KindToKindId {
171 static const NodeKindId Id = NKI_None;
174 struct KindToKindId<const T> : KindToKindId<T> {};
178 /// The id of the parent kind, or None if it has no parent.
180 /// Name of the kind.
183 static const KindInfo AllKindInfo[NKI_NumberOfKinds];
188 #define KIND_TO_KIND_ID(Class) \
189 template <> struct ASTNodeKind::KindToKindId<Class> { \
190 static const NodeKindId Id = NKI_##Class; \
192 KIND_TO_KIND_ID(CXXCtorInitializer)
193 KIND_TO_KIND_ID(TemplateArgument)
194 KIND_TO_KIND_ID(TemplateName)
195 KIND_TO_KIND_ID(NestedNameSpecifier)
196 KIND_TO_KIND_ID(NestedNameSpecifierLoc)
197 KIND_TO_KIND_ID(QualType)
198 KIND_TO_KIND_ID(TypeLoc)
199 KIND_TO_KIND_ID(Decl)
200 KIND_TO_KIND_ID(Stmt)
201 KIND_TO_KIND_ID(Type)
202 KIND_TO_KIND_ID(OMPClause)
203 #define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
204 #include "clang/AST/DeclNodes.inc"
205 #define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
206 #include "clang/AST/StmtNodes.inc"
207 #define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
208 #include "clang/AST/TypeNodes.def"
209 #define OPENMP_CLAUSE(TextualSpelling, Class) KIND_TO_KIND_ID(Class)
210 #include "clang/Basic/OpenMPKinds.def"
211 #undef KIND_TO_KIND_ID
213 inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) {
214 OS << K.asStringRef();
218 /// A dynamically typed AST node container.
220 /// Stores an AST node in a type safe way. This allows writing code that
221 /// works with different kinds of AST nodes, despite the fact that they don't
222 /// have a common base class.
224 /// Use \c create(Node) to create a \c DynTypedNode from an AST node,
225 /// and \c get<T>() to retrieve the node as type T if the types match.
227 /// See \c ASTNodeKind for which node base types are currently supported;
228 /// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
229 /// the supported base types.
232 /// Creates a \c DynTypedNode from \c Node.
233 template <typename T>
234 static DynTypedNode create(const T &Node) {
235 return BaseConverter<T>::create(Node);
238 /// Retrieve the stored node as type \c T.
240 /// Returns NULL if the stored node does not have a type that is
241 /// convertible to \c T.
243 /// For types that have identity via their pointer in the AST
244 /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
245 /// pointer points to the referenced AST node.
246 /// For other types (like \c QualType) the value is stored directly
247 /// in the \c DynTypedNode, and the returned pointer points at
248 /// the storage inside DynTypedNode. For those nodes, do not
249 /// use the pointer outside the scope of the DynTypedNode.
250 template <typename T>
251 const T *get() const {
252 return BaseConverter<T>::get(NodeKind, Storage.buffer);
255 /// Retrieve the stored node as type \c T.
257 /// Similar to \c get(), but asserts that the type is what we are expecting.
258 template <typename T>
259 const T &getUnchecked() const {
260 return BaseConverter<T>::getUnchecked(NodeKind, Storage.buffer);
263 ASTNodeKind getNodeKind() const { return NodeKind; }
265 /// Returns a pointer that identifies the stored AST node.
267 /// Note that this is not supported by all AST nodes. For AST nodes
268 /// that don't have a pointer-defined identity inside the AST, this
269 /// method returns NULL.
270 const void *getMemoizationData() const {
271 return NodeKind.hasPointerIdentity()
272 ? *reinterpret_cast<void *const *>(Storage.buffer)
276 /// Prints the node to the given output stream.
277 void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
279 /// Dumps the node to the given output stream.
280 void dump(llvm::raw_ostream &OS, SourceManager &SM) const;
282 /// For nodes which represent textual entities in the source code,
283 /// return their SourceRange. For all other nodes, return SourceRange().
284 SourceRange getSourceRange() const;
287 /// Imposes an order on \c DynTypedNode.
289 /// Supports comparison of nodes that support memoization.
290 /// FIXME: Implement comparison for other node types (currently
291 /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
292 bool operator<(const DynTypedNode &Other) const {
293 if (!NodeKind.isSame(Other.NodeKind))
294 return NodeKind < Other.NodeKind;
296 if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
297 return getUnchecked<QualType>().getAsOpaquePtr() <
298 Other.getUnchecked<QualType>().getAsOpaquePtr();
300 if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) {
301 auto TLA = getUnchecked<TypeLoc>();
302 auto TLB = Other.getUnchecked<TypeLoc>();
303 return std::make_pair(TLA.getType().getAsOpaquePtr(),
304 TLA.getOpaqueData()) <
305 std::make_pair(TLB.getType().getAsOpaquePtr(),
306 TLB.getOpaqueData());
309 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
311 auto NNSLA = getUnchecked<NestedNameSpecifierLoc>();
312 auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>();
313 return std::make_pair(NNSLA.getNestedNameSpecifier(),
314 NNSLA.getOpaqueData()) <
315 std::make_pair(NNSLB.getNestedNameSpecifier(),
316 NNSLB.getOpaqueData());
319 assert(getMemoizationData() && Other.getMemoizationData());
320 return getMemoizationData() < Other.getMemoizationData();
322 bool operator==(const DynTypedNode &Other) const {
323 // DynTypedNode::create() stores the exact kind of the node in NodeKind.
324 // If they contain the same node, their NodeKind must be the same.
325 if (!NodeKind.isSame(Other.NodeKind))
328 // FIXME: Implement for other types.
329 if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
330 return getUnchecked<QualType>() == Other.getUnchecked<QualType>();
332 if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind))
333 return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>();
335 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(NodeKind))
336 return getUnchecked<NestedNameSpecifierLoc>() ==
337 Other.getUnchecked<NestedNameSpecifierLoc>();
339 assert(getMemoizationData() && Other.getMemoizationData());
340 return getMemoizationData() == Other.getMemoizationData();
342 bool operator!=(const DynTypedNode &Other) const {
343 return !operator==(Other);
347 /// Hooks for using DynTypedNode as a key in a DenseMap.
348 struct DenseMapInfo {
349 static inline DynTypedNode getEmptyKey() {
351 Node.NodeKind = ASTNodeKind::DenseMapInfo::getEmptyKey();
354 static inline DynTypedNode getTombstoneKey() {
356 Node.NodeKind = ASTNodeKind::DenseMapInfo::getTombstoneKey();
359 static unsigned getHashValue(const DynTypedNode &Val) {
360 // FIXME: Add hashing support for the remaining types.
361 if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(Val.NodeKind)) {
362 auto TL = Val.getUnchecked<TypeLoc>();
363 return llvm::hash_combine(TL.getType().getAsOpaquePtr(),
367 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
369 auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>();
370 return llvm::hash_combine(NNSL.getNestedNameSpecifier(),
371 NNSL.getOpaqueData());
374 assert(Val.getMemoizationData());
375 return llvm::hash_value(Val.getMemoizationData());
377 static bool isEqual(const DynTypedNode &LHS, const DynTypedNode &RHS) {
378 auto Empty = ASTNodeKind::DenseMapInfo::getEmptyKey();
379 auto TombStone = ASTNodeKind::DenseMapInfo::getTombstoneKey();
380 return (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, Empty) &&
381 ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, Empty)) ||
382 (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, TombStone) &&
383 ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, TombStone)) ||
389 /// Takes care of converting from and to \c T.
390 template <typename T, typename EnablerT = void> struct BaseConverter;
392 /// Converter that uses dyn_cast<T> from a stored BaseT*.
393 template <typename T, typename BaseT> struct DynCastPtrConverter {
394 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
395 if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))
396 return &getUnchecked(NodeKind, Storage);
399 static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
400 assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind));
401 return *cast<T>(static_cast<const BaseT *>(
402 *reinterpret_cast<const void *const *>(Storage)));
404 static DynTypedNode create(const BaseT &Node) {
406 Result.NodeKind = ASTNodeKind::getFromNode(Node);
407 new (Result.Storage.buffer) const void *(&Node);
412 /// Converter that stores T* (by pointer).
413 template <typename T> struct PtrConverter {
414 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
415 if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
416 return &getUnchecked(NodeKind, Storage);
419 static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
420 assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind));
421 return *static_cast<const T *>(
422 *reinterpret_cast<const void *const *>(Storage));
424 static DynTypedNode create(const T &Node) {
426 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
427 new (Result.Storage.buffer) const void *(&Node);
432 /// Converter that stores T (by value).
433 template <typename T> struct ValueConverter {
434 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
435 if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
436 return reinterpret_cast<const T *>(Storage);
439 static const T &getUnchecked(ASTNodeKind NodeKind, const char Storage[]) {
440 assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind));
441 return *reinterpret_cast<const T *>(Storage);
443 static DynTypedNode create(const T &Node) {
445 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
446 new (Result.Storage.buffer) T(Node);
451 ASTNodeKind NodeKind;
453 /// Stores the data of the node.
455 /// Note that we can store \c Decls, \c Stmts, \c Types,
456 /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
457 /// guaranteed to be unique pointers pointing to dedicated storage in the AST.
458 /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and
459 /// \c TemplateArguments on the other hand do not have storage or unique
460 /// pointers and thus need to be stored by value.
461 llvm::AlignedCharArrayUnion<const void *, TemplateArgument,
462 NestedNameSpecifierLoc, QualType,
466 template <typename T>
467 struct DynTypedNode::BaseConverter<
468 T, typename std::enable_if<std::is_base_of<Decl, T>::value>::type>
469 : public DynCastPtrConverter<T, Decl> {};
471 template <typename T>
472 struct DynTypedNode::BaseConverter<
473 T, typename std::enable_if<std::is_base_of<Stmt, T>::value>::type>
474 : public DynCastPtrConverter<T, Stmt> {};
476 template <typename T>
477 struct DynTypedNode::BaseConverter<
478 T, typename std::enable_if<std::is_base_of<Type, T>::value>::type>
479 : public DynCastPtrConverter<T, Type> {};
481 template <typename T>
482 struct DynTypedNode::BaseConverter<
483 T, typename std::enable_if<std::is_base_of<OMPClause, T>::value>::type>
484 : public DynCastPtrConverter<T, OMPClause> {};
487 struct DynTypedNode::BaseConverter<
488 NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
491 struct DynTypedNode::BaseConverter<
492 CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
495 struct DynTypedNode::BaseConverter<
496 TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
499 struct DynTypedNode::BaseConverter<
500 TemplateName, void> : public ValueConverter<TemplateName> {};
503 struct DynTypedNode::BaseConverter<
504 NestedNameSpecifierLoc,
505 void> : public ValueConverter<NestedNameSpecifierLoc> {};
508 struct DynTypedNode::BaseConverter<QualType,
509 void> : public ValueConverter<QualType> {};
512 struct DynTypedNode::BaseConverter<
513 TypeLoc, void> : public ValueConverter<TypeLoc> {};
515 // The only operation we allow on unsupported types is \c get.
516 // This allows to conveniently use \c DynTypedNode when having an arbitrary
517 // AST node that is not supported, but prevents misuse - a user cannot create
518 // a DynTypedNode from arbitrary types.
519 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
520 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
525 } // end namespace ast_type_traits
526 } // end namespace clang
531 struct DenseMapInfo<clang::ast_type_traits::ASTNodeKind>
532 : clang::ast_type_traits::ASTNodeKind::DenseMapInfo {};
535 struct DenseMapInfo<clang::ast_type_traits::DynTypedNode>
536 : clang::ast_type_traits::DynTypedNode::DenseMapInfo {};
538 } // end namespace llvm