diff --git a/clang/include/clang/AST/RecursiveASTEnterExitVisitor.h b/clang/include/clang/AST/RecursiveASTEnterExitVisitor.h new file mode 100644 index 0000000000000..fd275cc75e9a5 --- /dev/null +++ b/clang/include/clang/AST/RecursiveASTEnterExitVisitor.h @@ -0,0 +1,4187 @@ +//===--- RecursiveASTEnterExitVisitor.h - Recursive AST Visitor ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the RecursiveASTEnterExitVisitor interface, which recursively +// traverses the entire AST. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ENTEREXITRECURSIVEASTVISITOR_H +#define LLVM_CLANG_AST_ENTEREXITRECURSIVEASTVISITOR_H + +#include "clang/AST/ASTConcept.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenACC.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprConcepts.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenACCClause.h" +#include "clang/AST/OpenMPClause.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenACC.h" +#include "clang/AST/StmtOpenMP.h" +#include "clang/AST/StmtSYCL.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include +#include +#include + +namespace clang { + +// A helper macro to implement short-circuiting when recursing. It +// invokes CALL_EXPR, which must be a method call, on the derived +// object (s.t. a user of RecursiveASTEnterExitVisitor can override the method +// in CALL_EXPR). +#define TRY_TO(CALL_EXPR) \ + do { \ + if (!getDerived().CALL_EXPR) \ + return false; \ + } while (false) + +/// A class that does preorder or postorder +/// depth-first traversal on the entire Clang AST and visits each node. +/// +/// This class performs three distinct tasks: +/// 1. traverse the AST (i.e. go to each node); +/// 2. at a given node, walk up the class hierarchy, starting from +/// the node's dynamic type, until the top-most class (e.g. Stmt, +/// Decl, or Type) is reached. +/// 3. given a (node, class) combination, where 'class' is some base +/// class of the dynamic type of 'node', call a user-overridable +/// function to actually visit the node. +/// +/// These tasks are done by three groups of methods, respectively: +/// 1. TraverseDecl(Decl *x) does task #1. It is the entry point +/// for traversing an AST rooted at x. This method simply +/// dispatches (i.e. forwards) to TraverseFoo(Foo *x) where Foo +/// is the dynamic type of *x, which calls WalkUpFromFoo(x) and +/// then recursively visits the child nodes of x. +/// TraverseStmt(Stmt *x) and TraverseType(QualType x) work +/// similarly. +/// 2. WalkUpFromFoo(Foo *x) does task #2. It does not try to visit +/// any child node of x. Instead, it first calls WalkUpFromBar(x) +/// where Bar is the direct parent class of Foo (unless Foo has +/// no parent), and then calls VisitFoo(x) (see the next list item). +/// 3. VisitFoo(Foo *x) does task #3. +/// +/// These three method groups are tiered (Traverse* > WalkUpFrom* > +/// Visit*). A method (e.g. Traverse*) may call methods from the same +/// tier (e.g. other Traverse*) or one tier lower (e.g. WalkUpFrom*). +/// It may not call methods from a higher tier. +/// +/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar +/// is Foo's super class) before calling VisitFoo(), the result is +/// that the Visit*() methods for a given node are called in the +/// top-down order (e.g. for a node of type NamespaceDecl, the order will +/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()). +/// +/// This scheme guarantees that all Visit*() calls for the same AST +/// node are grouped together. In other words, Visit*() methods for +/// different nodes are never interleaved. +/// +/// Clients of this visitor should subclass the visitor (providing +/// themselves as the template argument, using the curiously recurring +/// template pattern) and override any of the Traverse*, WalkUpFrom*, +/// and Visit* methods for declarations, types, statements, +/// expressions, or other AST nodes where the visitor should customize +/// behavior. Most users only need to override Visit*. Advanced +/// users may override Traverse* and WalkUpFrom* to implement custom +/// traversal strategies. Returning false from one of these overridden +/// functions will abort the entire traversal. +/// +/// By default, this visitor tries to visit every part of the explicit +/// source code exactly once. The default policy towards templates +/// is to descend into the 'pattern' class or function body, not any +/// explicit or implicit instantiations. Explicit specializations +/// are still visited, and the patterns of partial specializations +/// are visited separately. This behavior can be changed by +/// overriding shouldVisitTemplateInstantiations() in the derived class +/// to return true, in which case all known implicit and explicit +/// instantiations will be visited at the same time as the pattern +/// from which they were produced. +/// +/// By default, this visitor preorder traverses the AST. If postorder traversal +/// is needed, the \c shouldTraversePostOrder method needs to be overridden +/// to return \c true. +template class RecursiveASTEnterExitVisitor { +public: + /// A queue used for performing data recursion over statements. + /// Parameters involving this type are used to implement data + /// recursion over Stmts and Exprs within this class, and should + /// typically not be explicitly specified by derived classes. + /// The bool bit indicates whether the statement has been traversed or not. + typedef SmallVectorImpl> + DataRecursionQueue; + + /// Return a reference to the derived class. + Derived &getDerived() { return *static_cast(this); } + + /// Return whether this visitor should recurse into + /// template instantiations. + bool shouldVisitTemplateInstantiations() const { return false; } + + /// Return whether this visitor should recurse into the types of + /// TypeLocs. + bool shouldWalkTypesOfTypeLocs() const { return true; } + + /// Return whether this visitor should recurse into implicit + /// code, e.g., implicit constructors and destructors. + bool shouldVisitImplicitCode() const { return false; } + + /// Return whether this visitor should recurse into lambda body + bool shouldVisitLambdaBody() const { return true; } + + /// Return whether this visitor should traverse post-order. + bool shouldTraversePostOrder() const { return false; } + + /// Recursively visits an entire AST, starting from the TranslationUnitDecl. + /// \returns false if visitation was terminated early. + bool TraverseAST(ASTContext &AST) { + // Currently just an alias for TraverseDecl(TUDecl), but kept in case + // we change the implementation again. + return getDerived().TraverseDecl(AST.getTranslationUnitDecl()); + } + + /// Recursively visit a statement or expression, by + /// dispatching to Traverse*() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is nullptr). + bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr); + + /// Invoked before visiting a statement or expression via data recursion. + /// + /// \returns false to skip visiting the node, true otherwise. + bool dataTraverseStmtPre(Stmt *S) { return true; } + + /// Invoked after visiting a statement or expression via data recursion. + /// This is not invoked if the previously invoked \c dataTraverseStmtPre + /// returned false. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool dataTraverseStmtPost(Stmt *S) { return true; } + + /// Recursively visit a type, by dispatching to + /// Traverse*Type() based on the argument's getTypeClass() property. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type). + bool TraverseType(QualType T); + + /// Recursively visit a type with location, by dispatching to + /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type location). + bool TraverseTypeLoc(TypeLoc TL); + + /// Recursively visit an attribute, by dispatching to + /// Traverse*Attr() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type location). + bool TraverseAttr(Attr *At); + + /// Recursively visit a declaration, by dispatching to + /// Traverse*Decl() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is NULL). + bool TraverseDecl(Decl *D); + + /// Recursively visit a C++ nested-name-specifier. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// Recursively visit a C++ nested-name-specifier with location + /// information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); + + /// Recursively visit a name with its location information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo); + + /// Recursively visit a template name and dispatch to the + /// appropriate method. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseTemplateName(TemplateName Template); + + /// Recursively visit a template argument and dispatch to the + /// appropriate method for the argument type. + /// + /// \returns false if the visitation was terminated early, true otherwise. + // FIXME: migrate callers to TemplateArgumentLoc instead. + bool TraverseTemplateArgument(const TemplateArgument &Arg); + + /// Recursively visit a template argument location and dispatch to the + /// appropriate method for the argument type. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc); + + /// Recursively visit a set of template arguments. + /// This can be overridden by a subclass, but it's not expected that + /// will be needed -- this visitor always dispatches to another. + /// + /// \returns false if the visitation was terminated early, true otherwise. + // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead. + bool TraverseTemplateArguments(ArrayRef Args); + + /// Recursively visit a base specifier. This can be overridden by a + /// subclass. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base); + + /// Recursively visit a constructor initializer. This + /// automatically dispatches to another visitor for the initializer + /// expression, but not for the name of the initializer, so may + /// be overridden for clients that need access to the name. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseConstructorInitializer(CXXCtorInitializer *Init); + + /// Recursively visit a lambda capture. \c Init is the expression that + /// will be used to initialize the capture. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, + Expr *Init); + + /// Recursively visit the syntactic or semantic form of an + /// initialization list. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseSynOrSemInitListExpr(InitListExpr *S, + DataRecursionQueue *Queue = nullptr); + + /// Recursively visit an Objective-C protocol reference with location + /// information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc); + + /// Recursively visit concept reference with location information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseConceptReference(ConceptReference *CR); + + // Visit concept reference. + bool VisitConceptReference(ConceptReference *CR) { return true; } + // ---- Methods on Attrs ---- + + // Visit an attribute. + bool VisitAttr(Attr *A) { return true; } + +// Declare Traverse* and empty Visit* for all Attr classes. +#define ATTR_VISITOR_DECLS_ONLY +#include "clang/AST/AttrVisitor.inc" +#undef ATTR_VISITOR_DECLS_ONLY + +// ---- Methods on Stmts ---- + + Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); } + +private: + // Traverse the given statement. If the most-derived traverse function takes a + // data recursion queue, pass it on; otherwise, discard it. Note that the + // first branch of this conditional must compile whether or not the derived + // class can take a queue, so if we're taking the second arm, make the first + // arm call our function rather than the derived class version. +#define TRAVERSE_STMT_BASE(NAME, CLASS, VAR, QUEUE) \ + (::clang::detail::has_same_member_pointer_type< \ + decltype(&RecursiveASTEnterExitVisitor::Traverse##NAME), \ + decltype(&Derived::Traverse##NAME)>::value \ + ? static_cast::value, \ + Derived &, RecursiveASTEnterExitVisitor &>>(*this) \ + .Traverse##NAME(static_cast(VAR), QUEUE) \ + : getDerived().Traverse##NAME(static_cast(VAR))) + +// Try to traverse the given statement, or enqueue it if we're performing data +// recursion in the middle of traversing another statement. Can only be called +// from within a DEF_TRAVERSE_STMT body or similar context. +#define TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S) \ + do { \ + if (!TRAVERSE_STMT_BASE(Stmt, Stmt, S, Queue)) \ + return false; \ + } while (false) + +public: +// Declare Traverse*() for all concrete Stmt classes. +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + bool Traverse##CLASS(CLASS *S, DataRecursionQueue *Queue = nullptr); +#include "clang/AST/StmtNodes.inc" + // The above header #undefs ABSTRACT_STMT and STMT upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Stmt classes. + bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitEnterStmt(S) && getDerived().VisitStmt(S) && getDerived().VisitExitStmt(S); } + bool VisitEnterStmt(Stmt *S) { return true; } + bool VisitStmt(Stmt *S) { return true; } + bool VisitExitStmt(Stmt *S) { return true; } +#define STMT(CLASS, PARENT) \ + bool WalkUpFrom##CLASS(CLASS *S) { \ + TRY_TO(WalkUpFrom##PARENT(S)); \ + TRY_TO(VisitEnter##CLASS(S)); \ + TRY_TO(Visit##CLASS(S)); \ + TRY_TO(VisitExit##CLASS(S)); \ + return true; \ + } \ + bool VisitEnter##CLASS(CLASS *S) { return true; } \ + bool Visit##CLASS(CLASS *S) { return true; } \ + bool VisitExit##CLASS(CLASS *S) { return true; } +#include "clang/AST/StmtNodes.inc" + +// ---- Methods on Types ---- +// FIXME: revamp to take TypeLoc's rather than Types. + +// Declare Traverse*() for all concrete Type classes. +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T); +#include "clang/AST/TypeNodes.inc" + // The above header #undefs ABSTRACT_TYPE and TYPE upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Type classes. + bool WalkUpFromType(Type *T) { return getDerived().VisitEnterType(T) && getDerived().VisitType(T) && getDerived().VisitExitType(T); } + bool VisitEnterType(Type *T) { return true; } + bool VisitType(Type *T) { return true; } + bool VisitExitType(Type *T) { return true; } +#define TYPE(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Type(CLASS##Type *T) { \ + TRY_TO(WalkUpFrom##BASE(T)); \ + TRY_TO(VisitEnter##CLASS##Type(T)); \ + TRY_TO(Visit##CLASS##Type(T)); \ + TRY_TO(VisitExit##CLASS##Type(T)); \ + return true; \ + } \ + bool VisitEnter##CLASS##Type(CLASS##Type *T) { return true; } \ + bool Visit##CLASS##Type(CLASS##Type *T) { return true; } \ + bool VisitExit##CLASS##Type(CLASS##Type *T) { return true; } +#include "clang/AST/TypeNodes.inc" + +// ---- Methods on TypeLocs ---- +// FIXME: this currently just calls the matching Type methods + +// Declare Traverse*() for all concrete TypeLoc classes. +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); +#include "clang/AST/TypeLocNodes.def" + // The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all TypeLoc classes. + bool WalkUpFromTypeLoc(TypeLoc TL) { + return getDerived().VisitEnterTypeLoc(TL) && + getDerived().VisitTypeLoc(TL) && + getDerived().VisitExitTypeLoc(TL); + } + bool VisitEnterTypeLoc(TypeLoc TL) { return true; } + bool VisitTypeLoc(TypeLoc TL) { return true; } + bool VisitExitTypeLoc(TypeLoc TL) { return true; } + + // QualifiedTypeLoc and UnqualTypeLoc are not declared in + // TypeNodes.inc and thus need to be handled specially. + bool WalkUpFromQualifiedTypeLoc(QualifiedTypeLoc TL) { + return getDerived().VisitEnterUnqualTypeLoc(TL.getUnqualifiedLoc()) + && getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc()) + && getDerived().VisitExitUnqualTypeLoc(TL.getUnqualifiedLoc()); + } + bool VisitEnterQualifiedTypeLoc(QualifiedTypeLoc TL) { return true; } + bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { return true; } + bool VisitExitQualifiedTypeLoc(QualifiedTypeLoc TL) { return true; } + + bool WalkUpFromUnqualTypeLoc(UnqualTypeLoc TL) { + return getDerived().VisitEnterUnqualTypeLoc(TL.getUnqualifiedLoc()) + && getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc()) + && getDerived().VisitExitUnqualTypeLoc(TL.getUnqualifiedLoc()); + } + bool VisitEnterUnqualTypeLoc(UnqualTypeLoc TL) { return true; } + bool VisitUnqualTypeLoc(UnqualTypeLoc TL) { return true; } + bool VisitExitUnqualTypeLoc(UnqualTypeLoc TL) { return true; } + +// Note that BASE includes trailing 'Type' which CLASS doesn't. +#define TYPE(CLASS, BASE) \ + bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ + TRY_TO(WalkUpFrom##BASE##Loc(TL)); \ + TRY_TO(VisitEnter##CLASS##TypeLoc(TL)); \ + TRY_TO(Visit##CLASS##TypeLoc(TL)); \ + TRY_TO(VisitExit##CLASS##TypeLoc(TL)); \ + return true; \ + } \ + bool VisitEnter##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; } \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; } \ + bool VisitExit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; } +#include "clang/AST/TypeNodes.inc" + +// ---- Methods on Decls ---- + +// Declare Traverse*() for all concrete Decl classes. +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) bool Traverse##CLASS##Decl(CLASS##Decl *D); +#include "clang/AST/DeclNodes.inc" + // The above header #undefs ABSTRACT_DECL and DECL upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Decl classes. + // Define WalkUpFrom*() and empty Visit*() for all Decl classes. + bool WalkUpFromDecl(Decl *D) { + return getDerived().VisitEnterDecl(D) && + getDerived().VisitDecl(D) && + getDerived().VisitExitDecl(D); + } + bool VisitEnterDecl(Decl *D) { return true; } + bool VisitDecl(Decl *D) { return true; } + bool VisitExitDecl(Decl *D) { return true; } +#define DECL(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \ + TRY_TO(WalkUpFrom##BASE(D)); \ + TRY_TO(VisitEnter##CLASS##Decl(D)); \ + TRY_TO(Visit##CLASS##Decl(D)); \ + TRY_TO(VisitExit##CLASS##Decl(D)); \ + return true; \ + } \ + bool VisitEnter##CLASS##Decl(CLASS##Decl *D) { return true; } \ + bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; } \ + bool VisitExit##CLASS##Decl(CLASS##Decl *D) { return true; } +#include "clang/AST/DeclNodes.inc" + + bool canIgnoreChildDeclWhileTraversingDeclContext(const Decl *Child); + +#define DEF_TRAVERSE_TMPL_INST(TMPLDECLKIND) \ + bool TraverseTemplateInstantiations(TMPLDECLKIND##TemplateDecl *D); + DEF_TRAVERSE_TMPL_INST(Class) + DEF_TRAVERSE_TMPL_INST(Var) + DEF_TRAVERSE_TMPL_INST(Function) +#undef DEF_TRAVERSE_TMPL_INST + + bool TraverseTypeConstraint(const TypeConstraint *C); + + bool TraverseConceptRequirement(concepts::Requirement *R); + bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R); + bool TraverseConceptExprRequirement(concepts::ExprRequirement *R); + bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R); + + bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue); + +private: + // These are helper methods used by more than one Traverse* method. + bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); + + // Traverses template parameter lists of either a DeclaratorDecl or TagDecl. + template + bool TraverseDeclTemplateParameterLists(T *D); + + bool TraverseTemplateTypeParamDeclConstraints(const TemplateTypeParmDecl *D); + + bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, + unsigned Count); + bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL); + bool TraverseRecordHelper(RecordDecl *D); + bool TraverseCXXRecordHelper(CXXRecordDecl *D); + bool TraverseDeclaratorHelper(DeclaratorDecl *D); + bool TraverseDeclContextHelper(DeclContext *DC); + bool TraverseFunctionHelper(FunctionDecl *D); + bool TraverseVarHelper(VarDecl *D); + bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); + bool TraverseOMPLoopDirective(OMPLoopDirective *S); + bool TraverseOMPClause(OMPClause *C); +#define GEN_CLANG_CLAUSE_CLASS +#define CLAUSE_CLASS(Enum, Str, Class) bool Visit##Class(Class *C); +#include "llvm/Frontend/OpenMP/OMP.inc" + /// Process clauses with list of variables. + template bool VisitOMPClauseList(T *Node); + /// Process clauses with pre-initis. + bool VisitOMPClauseWithPreInit(OMPClauseWithPreInit *Node); + bool VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *Node); + + bool PostVisitStmt(Stmt *S); + bool TraverseOpenACCConstructStmt(OpenACCConstructStmt *S); + bool + TraverseOpenACCAssociatedStmtConstruct(OpenACCAssociatedStmtConstruct *S); + bool VisitOpenACCClauseList(ArrayRef); + bool VisitOpenACCClause(const OpenACCClause *); +}; + +template +bool RecursiveASTEnterExitVisitor::TraverseTypeConstraint( + const TypeConstraint *C) { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO(TraverseConceptReference(C->getConceptReference())); + return true; + } + if (Expr *IDC = C->getImmediatelyDeclaredConstraint()) { + TRY_TO(TraverseStmt(IDC)); + } else { + // Avoid traversing the ConceptReference in the TypeConstraint + // if we have an immediately-declared-constraint, otherwise + // we'll end up visiting the concept and the arguments in + // the TC twice. + TRY_TO(TraverseConceptReference(C->getConceptReference())); + } + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseConceptRequirement( + concepts::Requirement *R) { + switch (R->getKind()) { + case concepts::Requirement::RK_Type: + return getDerived().TraverseConceptTypeRequirement( + cast(R)); + case concepts::Requirement::RK_Simple: + case concepts::Requirement::RK_Compound: + return getDerived().TraverseConceptExprRequirement( + cast(R)); + case concepts::Requirement::RK_Nested: + return getDerived().TraverseConceptNestedRequirement( + cast(R)); + } + llvm_unreachable("unexpected case"); +} + +template +bool RecursiveASTEnterExitVisitor::dataTraverseNode(Stmt *S, + DataRecursionQueue *Queue) { + // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt. + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: + break; +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + return TRAVERSE_STMT_BASE(CLASS, CLASS, S, Queue); +#include "clang/AST/StmtNodes.inc" + } + + return true; +} + +#undef DISPATCH_STMT + +template +bool RecursiveASTEnterExitVisitor::TraverseConceptTypeRequirement( + concepts::TypeRequirement *R) { + if (R->isSubstitutionFailure()) + return true; + return getDerived().TraverseTypeLoc(R->getType()->getTypeLoc()); +} + +template +bool RecursiveASTEnterExitVisitor::TraverseConceptExprRequirement( + concepts::ExprRequirement *R) { + if (!R->isExprSubstitutionFailure()) + TRY_TO(TraverseStmt(R->getExpr())); + auto &RetReq = R->getReturnTypeRequirement(); + if (RetReq.isTypeConstraint()) { + if (getDerived().shouldVisitImplicitCode()) { + TRY_TO(TraverseTemplateParameterListHelper( + RetReq.getTypeConstraintTemplateParameterList())); + } else { + // Template parameter list is implicit, visit constraint directly. + TRY_TO(TraverseTypeConstraint(RetReq.getTypeConstraint())); + } + } + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseConceptNestedRequirement( + concepts::NestedRequirement *R) { + if (!R->hasInvalidConstraint()) + return getDerived().TraverseStmt(R->getConstraintExpr()); + return true; +} + +template +bool RecursiveASTEnterExitVisitor::PostVisitStmt(Stmt *S) { + // In pre-order traversal mode, each Traverse##STMT method is responsible for + // calling WalkUpFrom. Therefore, if the user overrides Traverse##STMT and + // does not call the default implementation, the WalkUpFrom callback is not + // called. Post-order traversal mode should provide the same behavior + // regarding method overrides. + // + // In post-order traversal mode the Traverse##STMT method, when it receives a + // DataRecursionQueue, can't call WalkUpFrom after traversing children because + // it only enqueues the children and does not traverse them. TraverseStmt + // traverses the enqueued children, and we call WalkUpFrom here. + // + // However, to make pre-order and post-order modes identical with regards to + // whether they call WalkUpFrom at all, we call WalkUpFrom if and only if the + // user did not override the Traverse##STMT method. We implement the override + // check with isSameMethod calls below. + + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: + break; +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + if (::clang::detail::isSameMethod(&RecursiveASTEnterExitVisitor::Traverse##CLASS, \ + &Derived::Traverse##CLASS)) { \ + TRY_TO(WalkUpFrom##CLASS(static_cast(S))); \ + } \ + break; +#define INITLISTEXPR(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + if (::clang::detail::isSameMethod(&RecursiveASTEnterExitVisitor::Traverse##CLASS, \ + &Derived::Traverse##CLASS)) { \ + auto ILE = static_cast(S); \ + if (auto Syn = ILE->isSemanticForm() ? ILE->getSyntacticForm() : ILE) \ + TRY_TO(WalkUpFrom##CLASS(Syn)); \ + if (auto Sem = ILE->isSemanticForm() ? ILE : ILE->getSemanticForm()) \ + TRY_TO(WalkUpFrom##CLASS(Sem)); \ + } \ + break; +#include "clang/AST/StmtNodes.inc" + } + + return true; +} + +#undef DISPATCH_STMT + +// Inlining this method can lead to large code size and compile-time increases +// without any benefit to runtime performance. +template +LLVM_ATTRIBUTE_NOINLINE bool +RecursiveASTEnterExitVisitor::TraverseStmt(Stmt *S, DataRecursionQueue *Queue) { + if (!S) + return true; + + if (Queue) { + Queue->push_back({S, false}); + return true; + } + + SmallVector, 8> LocalQueue; + LocalQueue.push_back({S, false}); + + while (!LocalQueue.empty()) { + auto &CurrSAndVisited = LocalQueue.back(); + Stmt *CurrS = CurrSAndVisited.getPointer(); + bool Visited = CurrSAndVisited.getInt(); + if (Visited) { + LocalQueue.pop_back(); + TRY_TO(dataTraverseStmtPost(CurrS)); + if (getDerived().shouldTraversePostOrder()) { + TRY_TO(PostVisitStmt(CurrS)); + } + continue; + } + + if (getDerived().dataTraverseStmtPre(CurrS)) { + CurrSAndVisited.setInt(true); + size_t N = LocalQueue.size(); + TRY_TO(dataTraverseNode(CurrS, &LocalQueue)); + // Process new children in the order they were added. + std::reverse(LocalQueue.begin() + N, LocalQueue.end()); + } else { + LocalQueue.pop_back(); + } + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseType(QualType T) { + if (T.isNull()) + return true; + + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) \ + case Type::CLASS: \ + return getDerived().Traverse##CLASS##Type( \ + static_cast(const_cast(T.getTypePtr()))); +#include "clang/AST/TypeNodes.inc" + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseTypeLoc(TypeLoc TL) { + if (TL.isNull()) + return true; + + switch (TL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) \ + case TypeLoc::CLASS: \ + return getDerived().Traverse##CLASS##TypeLoc(TL.castAs()); +#include "clang/AST/TypeLocNodes.def" + } + + return true; +} + +// Define the Traverse*Attr(Attr* A) methods +#define VISITORCLASS RecursiveASTEnterExitVisitor +#include "clang/AST/AttrVisitor.inc" +#undef VISITORCLASS + +template +bool RecursiveASTEnterExitVisitor::TraverseDecl(Decl *D) { + if (!D) + return true; + + // As a syntax visitor, by default we want to ignore declarations for + // implicit declarations (ones not typed explicitly by the user). + if (!getDerived().shouldVisitImplicitCode()) { + if (D->isImplicit()) { + // For an implicit template type parameter, its type constraints are not + // implicit and are not represented anywhere else. We still need to visit + // them. + if (auto *TTPD = dyn_cast(D)) + return TraverseTemplateTypeParamDeclConstraints(TTPD); + return true; + } + + // Deduction guides for alias templates are always synthesized, so they + // should not be traversed unless shouldVisitImplicitCode() returns true. + // + // It's important to note that checking the implicit bit is not efficient + // for the alias case. For deduction guides synthesized from explicit + // user-defined deduction guides, we must maintain the explicit bit to + // ensure correct overload resolution. + if (auto *FTD = dyn_cast(D)) + if (llvm::isa_and_present( + FTD->getDeclName().getCXXDeductionGuideTemplate())) + return true; + } + + switch (D->getKind()) { +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) \ + case Decl::CLASS: \ + if (!getDerived().Traverse##CLASS##Decl(static_cast(D))) \ + return false; \ + break; +#include "clang/AST/DeclNodes.inc" + } + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseNestedNameSpecifier( + NestedNameSpecifier *NNS) { + if (!NNS) + return true; + + if (NNS->getPrefix()) + TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix())); + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + return true; + + case NestedNameSpecifier::TypeSpec: + TRY_TO(TraverseType(QualType(NNS->getAsType(), 0))); + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseNestedNameSpecifierLoc( + NestedNameSpecifierLoc NNS) { + if (!NNS) + return true; + + if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) + TRY_TO(TraverseNestedNameSpecifierLoc(Prefix)); + + switch (NNS.getNestedNameSpecifier()->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + return true; + + case NestedNameSpecifier::TypeSpec: + TRY_TO(TraverseTypeLoc(NNS.getTypeLoc())); + break; + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseDeclarationNameInfo( + DeclarationNameInfo NameInfo) { + switch (NameInfo.getName().getNameKind()) { + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo()) + TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc())); + break; + + case DeclarationName::CXXDeductionGuideName: + TRY_TO(TraverseTemplateName( + TemplateName(NameInfo.getName().getCXXDeductionGuideTemplate()))); + break; + + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + break; + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateName(TemplateName Template) { + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { + TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier())); + } else if (QualifiedTemplateName *QTN = + Template.getAsQualifiedTemplateName()) { + if (QTN->getQualifier()) { + TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier())); + } + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateArgument( + const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::StructuralValue: + return true; + + case TemplateArgument::Type: + return getDerived().TraverseType(Arg.getAsType()); + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return getDerived().TraverseStmt(Arg.getAsExpr()); + + case TemplateArgument::Pack: + return getDerived().TraverseTemplateArguments(Arg.pack_elements()); + } + + return true; +} + +// FIXME: no template name location? +// FIXME: no source locations for a template argument pack? +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateArgumentLoc( + const TemplateArgumentLoc &ArgLoc) { + const TemplateArgument &Arg = ArgLoc.getArgument(); + + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::StructuralValue: + return true; + + case TemplateArgument::Type: { + // FIXME: how can TSI ever be NULL? + if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo()) + return getDerived().TraverseTypeLoc(TSI->getTypeLoc()); + else + return getDerived().TraverseType(Arg.getAsType()); + } + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + if (ArgLoc.getTemplateQualifierLoc()) + TRY_TO(getDerived().TraverseNestedNameSpecifierLoc( + ArgLoc.getTemplateQualifierLoc())); + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return getDerived().TraverseStmt(ArgLoc.getSourceExpression()); + + case TemplateArgument::Pack: + return getDerived().TraverseTemplateArguments(Arg.pack_elements()); + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateArguments( + ArrayRef Args) { + for (const TemplateArgument &Arg : Args) + TRY_TO(TraverseTemplateArgument(Arg)); + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseConstructorInitializer( + CXXCtorInitializer *Init) { + if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc())); + + if (Init->isWritten() || getDerived().shouldVisitImplicitCode()) + TRY_TO(TraverseStmt(Init->getInit())); + + return true; +} + +template +bool +RecursiveASTEnterExitVisitor::TraverseLambdaCapture(LambdaExpr *LE, + const LambdaCapture *C, + Expr *Init) { + if (LE->isInitCapture(C)) + TRY_TO(TraverseDecl(C->getCapturedVar())); + else + TRY_TO(TraverseStmt(Init)); + return true; +} + +// ----------------- Type traversal ----------------- + +// This macro makes available a variable T, the passed-in type. +#define DEF_TRAVERSE_TYPE(TYPE, CODE) \ + template \ + bool RecursiveASTEnterExitVisitor::Traverse##TYPE(TYPE *T) { \ + if (!getDerived().shouldTraversePostOrder()) \ + TRY_TO(WalkUpFrom##TYPE(T)); \ + { CODE; } \ + if (getDerived().shouldTraversePostOrder()) \ + TRY_TO(WalkUpFrom##TYPE(T)); \ + return true; \ + } + +DEF_TRAVERSE_TYPE(BuiltinType, {}) + +DEF_TRAVERSE_TYPE(ComplexType, { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(PointerType, { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(BlockPointerType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(LValueReferenceType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(RValueReferenceType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(MemberPointerType, { + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); + if (T->isSugared()) + TRY_TO(TraverseType( + QualType(T->getMostRecentCXXRecordDecl()->getTypeForDecl(), 0))); + TRY_TO(TraverseType(T->getPointeeType())); +}) + +DEF_TRAVERSE_TYPE(AdjustedType, { TRY_TO(TraverseType(T->getOriginalType())); }) + +DEF_TRAVERSE_TYPE(DecayedType, { TRY_TO(TraverseType(T->getOriginalType())); }) + +DEF_TRAVERSE_TYPE(ConstantArrayType, { + TRY_TO(TraverseType(T->getElementType())); + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(const_cast(T->getSizeExpr()))); +}) + +DEF_TRAVERSE_TYPE(ArrayParameterType, { + TRY_TO(TraverseType(T->getElementType())); + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(const_cast(T->getSizeExpr()))); +}) + +DEF_TRAVERSE_TYPE(IncompleteArrayType, + { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(VariableArrayType, { + TRY_TO(TraverseType(T->getElementType())); + TRY_TO(TraverseStmt(T->getSizeExpr())); +}) + +DEF_TRAVERSE_TYPE(DependentSizedArrayType, { + TRY_TO(TraverseType(T->getElementType())); + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(T->getSizeExpr())); +}) + +DEF_TRAVERSE_TYPE(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(T->getAddrSpaceExpr())); + TRY_TO(TraverseType(T->getPointeeType())); +}) + +DEF_TRAVERSE_TYPE(DependentVectorType, { + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(T->getSizeExpr())); + TRY_TO(TraverseType(T->getElementType())); +}) + +DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, { + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(T->getSizeExpr())); + TRY_TO(TraverseType(T->getElementType())); +}) + +DEF_TRAVERSE_TYPE(VectorType, { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(ExtVectorType, { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(ConstantMatrixType, + { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(DependentSizedMatrixType, { + if (T->getRowExpr()) + TRY_TO(TraverseStmt(T->getRowExpr())); + if (T->getColumnExpr()) + TRY_TO(TraverseStmt(T->getColumnExpr())); + TRY_TO(TraverseType(T->getElementType())); +}) + +DEF_TRAVERSE_TYPE(FunctionNoProtoType, + { TRY_TO(TraverseType(T->getReturnType())); }) + +DEF_TRAVERSE_TYPE(FunctionProtoType, { + TRY_TO(TraverseType(T->getReturnType())); + + for (const auto &A : T->param_types()) { + TRY_TO(TraverseType(A)); + } + + for (const auto &E : T->exceptions()) { + TRY_TO(TraverseType(E)); + } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); +}) + +DEF_TRAVERSE_TYPE(UsingType, {}) +DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) +DEF_TRAVERSE_TYPE(TypedefType, {}) + +DEF_TRAVERSE_TYPE(TypeOfExprType, + { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) + +DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnmodifiedType())); }) + +DEF_TRAVERSE_TYPE(DecltypeType, + { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) + +DEF_TRAVERSE_TYPE(PackIndexingType, { + TRY_TO(TraverseType(T->getPattern())); + TRY_TO(TraverseStmt(T->getIndexExpr())); +}) + +DEF_TRAVERSE_TYPE(UnaryTransformType, { + TRY_TO(TraverseType(T->getBaseType())); + TRY_TO(TraverseType(T->getUnderlyingType())); +}) + +DEF_TRAVERSE_TYPE(AutoType, { + TRY_TO(TraverseType(T->getDeducedType())); + if (T->isConstrained()) { + TRY_TO(TraverseTemplateArguments(T->getTypeConstraintArguments())); + } +}) +DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + TRY_TO(TraverseType(T->getDeducedType())); +}) + +DEF_TRAVERSE_TYPE(RecordType, {}) +DEF_TRAVERSE_TYPE(EnumType, {}) +DEF_TRAVERSE_TYPE(TemplateTypeParmType, {}) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { + TRY_TO(TraverseType(T->getReplacementType())); +}) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { + TRY_TO(TraverseTemplateArgument(T->getArgumentPack())); +}) + +DEF_TRAVERSE_TYPE(TemplateSpecializationType, { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + TRY_TO(TraverseTemplateArguments(T->template_arguments())); +}) + +DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) + +DEF_TRAVERSE_TYPE(AttributedType, + { TRY_TO(TraverseType(T->getModifiedType())); }) + +DEF_TRAVERSE_TYPE(CountAttributedType, { + if (T->getCountExpr()) + TRY_TO(TraverseStmt(T->getCountExpr())); + TRY_TO(TraverseType(T->desugar())); +}) + +DEF_TRAVERSE_TYPE(BTFTagAttributedType, + { TRY_TO(TraverseType(T->getWrappedType())); }) + +DEF_TRAVERSE_TYPE(HLSLAttributedResourceType, + { TRY_TO(TraverseType(T->getWrappedType())); }) + +DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); }) + +DEF_TRAVERSE_TYPE(MacroQualifiedType, + { TRY_TO(TraverseType(T->getUnderlyingType())); }) + +DEF_TRAVERSE_TYPE(ElaboratedType, { + if (T->getQualifier()) { + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); + } + TRY_TO(TraverseType(T->getNamedType())); +}) + +DEF_TRAVERSE_TYPE(DependentNameType, + { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); }) + +DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { + const DependentTemplateStorage &S = T->getDependentTemplateName(); + TRY_TO(TraverseNestedNameSpecifier(S.getQualifier())); + TRY_TO(TraverseTemplateArguments(T->template_arguments())); +}) + +DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); }) + +DEF_TRAVERSE_TYPE(ObjCTypeParamType, {}) + +DEF_TRAVERSE_TYPE(ObjCInterfaceType, {}) + +DEF_TRAVERSE_TYPE(ObjCObjectType, { + // We have to watch out here because an ObjCInterfaceType's base + // type is itself. + if (T->getBaseType().getTypePtr() != T) + TRY_TO(TraverseType(T->getBaseType())); + for (auto typeArg : T->getTypeArgsAsWritten()) { + TRY_TO(TraverseType(typeArg)); + } +}) + +DEF_TRAVERSE_TYPE(ObjCObjectPointerType, + { TRY_TO(TraverseType(T->getPointeeType())); }) + +DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); }) + +DEF_TRAVERSE_TYPE(PipeType, { TRY_TO(TraverseType(T->getElementType())); }) + +DEF_TRAVERSE_TYPE(BitIntType, {}) +DEF_TRAVERSE_TYPE(DependentBitIntType, + { TRY_TO(TraverseStmt(T->getNumBitsExpr())); }) + +#undef DEF_TRAVERSE_TYPE + +// ----------------- TypeLoc traversal ----------------- + +// This macro makes available a variable TL, the passed-in TypeLoc. +// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc, +// in addition to WalkUpFrom* for the TypeLoc itself, such that existing +// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods +// continue to work. +#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \ + template \ + bool RecursiveASTEnterExitVisitor::Traverse##TYPE##Loc(TYPE##Loc TL) { \ + if (!getDerived().shouldTraversePostOrder()) { \ + TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ + if (getDerived().shouldWalkTypesOfTypeLocs()) \ + TRY_TO(WalkUpFrom##TYPE(const_cast(TL.getTypePtr()))); \ + } \ + { CODE; } \ + if (getDerived().shouldTraversePostOrder()) { \ + TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ + if (getDerived().shouldWalkTypesOfTypeLocs()) \ + TRY_TO(WalkUpFrom##TYPE(const_cast(TL.getTypePtr()))); \ + } \ + return true; \ + } + +template +bool +RecursiveASTEnterExitVisitor::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) { + // Move this over to the 'main' typeloc tree. Note that this is a + // move -- we pretend that we were really looking at the unqualified + // typeloc all along -- rather than a recursion, so we don't follow + // the normal CRTP plan of going through + // getDerived().TraverseTypeLoc. If we did, we'd be traversing + // twice for the same type (once as a QualifiedTypeLoc version of + // the type, once as an UnqualifiedTypeLoc version of the type), + // which in effect means we'd call VisitTypeLoc twice with the + // 'same' type. This solves that problem, at the cost of never + // seeing the qualified version of the type (unless the client + // subclasses TraverseQualifiedTypeLoc themselves). It's not a + // perfect solution. A perfect solution probably requires making + // QualifiedTypeLoc a wrapper around TypeLoc -- like QualType is a + // wrapper around Type* -- rather than being its own class in the + // type hierarchy. + return TraverseTypeLoc(TL.getUnqualifiedLoc()); +} + +DEF_TRAVERSE_TYPELOC(BuiltinType, {}) + +// FIXME: ComplexTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(ComplexType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +DEF_TRAVERSE_TYPELOC(PointerType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(BlockPointerType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(LValueReferenceType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(RValueReferenceType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +// We traverse this in the type case as well, but how is it not reached through +// the pointee type? +DEF_TRAVERSE_TYPELOC(MemberPointerType, { + if (NestedNameSpecifierLoc QL = TL.getQualifierLoc()) + TRY_TO(TraverseNestedNameSpecifierLoc(QL)); +// if (auto *TSI = TL.getClassTInfo()) +// TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); + else + TRY_TO(TraverseNestedNameSpecifier(TL.getTypePtr()->getQualifier())); +// TRY_TO(TraverseType(QualType(TL.getTypePtr()->getClass(), 0))); + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); +}) + +DEF_TRAVERSE_TYPELOC(AdjustedType, + { TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); }) + +DEF_TRAVERSE_TYPELOC(DecayedType, + { TRY_TO(TraverseTypeLoc(TL.getOriginalLoc())); }) + +template +bool RecursiveASTEnterExitVisitor::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { + // This isn't available for ArrayType, but is for the ArrayTypeLoc. + TRY_TO(TraverseStmt(TL.getSizeExpr())); + return true; +} + +DEF_TRAVERSE_TYPELOC(ConstantArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + TRY_TO(TraverseArrayTypeLocHelper(TL)); +}) + +DEF_TRAVERSE_TYPELOC(ArrayParameterType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + TRY_TO(TraverseArrayTypeLocHelper(TL)); +}) + +DEF_TRAVERSE_TYPELOC(IncompleteArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + TRY_TO(TraverseArrayTypeLocHelper(TL)); +}) + +DEF_TRAVERSE_TYPELOC(VariableArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + TRY_TO(TraverseArrayTypeLocHelper(TL)); +}) + +DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + TRY_TO(TraverseArrayTypeLocHelper(TL)); +}) + +DEF_TRAVERSE_TYPELOC(DependentAddressSpaceType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getAddrSpaceExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getPointeeType())); +}) + +// FIXME: order? why not size expr first? +// FIXME: base VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, { + if (TL.getTypePtr()->getSizeExpr()) + TRY_TO(TraverseStmt(TL.getTypePtr()->getSizeExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +// FIXME: VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(VectorType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +DEF_TRAVERSE_TYPELOC(DependentVectorType, { + if (TL.getTypePtr()->getSizeExpr()) + TRY_TO(TraverseStmt(TL.getTypePtr()->getSizeExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +// FIXME: size and attributes +// FIXME: base VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(ExtVectorType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +DEF_TRAVERSE_TYPELOC(ConstantMatrixType, { + TRY_TO(TraverseStmt(TL.getAttrRowOperand())); + TRY_TO(TraverseStmt(TL.getAttrColumnOperand())); + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +DEF_TRAVERSE_TYPELOC(DependentSizedMatrixType, { + TRY_TO(TraverseStmt(TL.getAttrRowOperand())); + TRY_TO(TraverseStmt(TL.getAttrColumnOperand())); + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); +}) + +DEF_TRAVERSE_TYPELOC(FunctionNoProtoType, + { TRY_TO(TraverseTypeLoc(TL.getReturnLoc())); }) + +// FIXME: location of exception specifications (attributes?) +DEF_TRAVERSE_TYPELOC(FunctionProtoType, { + TRY_TO(TraverseTypeLoc(TL.getReturnLoc())); + + const FunctionProtoType *T = TL.getTypePtr(); + + for (unsigned I = 0, E = TL.getNumParams(); I != E; ++I) { + if (TL.getParam(I)) { + TRY_TO(TraverseDecl(TL.getParam(I))); + } else if (I < T->getNumParams()) { + TRY_TO(TraverseType(T->getParamType(I))); + } + } + + for (const auto &E : T->exceptions()) { + TRY_TO(TraverseType(E)); + } + + if (Expr *NE = T->getNoexceptExpr()) + TRY_TO(TraverseStmt(NE)); +}) + +DEF_TRAVERSE_TYPELOC(UsingType, {}) +DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) +DEF_TRAVERSE_TYPELOC(TypedefType, {}) + +DEF_TRAVERSE_TYPELOC(TypeOfExprType, + { TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); }) + +DEF_TRAVERSE_TYPELOC(TypeOfType, { + TRY_TO(TraverseTypeLoc(TL.getUnmodifiedTInfo()->getTypeLoc())); +}) + +// FIXME: location of underlying expr +DEF_TRAVERSE_TYPELOC(DecltypeType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr())); +}) + +DEF_TRAVERSE_TYPELOC(PackIndexingType, { + TRY_TO(TraverseType(TL.getPattern())); + TRY_TO(TraverseStmt(TL.getTypePtr()->getIndexExpr())); +}) + +DEF_TRAVERSE_TYPELOC(UnaryTransformType, { + TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); +}) + +DEF_TRAVERSE_TYPELOC(AutoType, { + TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); + if (TL.isConstrained()) { + TRY_TO(TraverseConceptReference(TL.getConceptReference())); + } +}) + +DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { + TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); + TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); +}) + +DEF_TRAVERSE_TYPELOC(RecordType, {}) +DEF_TRAVERSE_TYPELOC(EnumType, {}) +DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {}) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { + TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType())); +}) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { + TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack())); +}) + +// FIXME: use the loc for the template name? +DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { + TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); + } +}) + +DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {}) + +DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); }) + +DEF_TRAVERSE_TYPELOC(MacroQualifiedType, + { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); }) + +DEF_TRAVERSE_TYPELOC(AttributedType, + { TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); }) + +DEF_TRAVERSE_TYPELOC(CountAttributedType, + { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); }) + +DEF_TRAVERSE_TYPELOC(BTFTagAttributedType, + { TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); }) + +DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType, + { TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); }) + +DEF_TRAVERSE_TYPELOC(ElaboratedType, { + if (TL.getQualifierLoc()) { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + } + TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc())); +}) + +DEF_TRAVERSE_TYPELOC(DependentNameType, { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); +}) + +DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, { + if (TL.getQualifierLoc()) { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + } + + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); + } +}) + +DEF_TRAVERSE_TYPELOC(PackExpansionType, + { TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); }) + +DEF_TRAVERSE_TYPELOC(ObjCTypeParamType, { + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { + ObjCProtocolLoc ProtocolLoc(TL.getProtocol(I), TL.getProtocolLoc(I)); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } +}) + +DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, {}) + +DEF_TRAVERSE_TYPELOC(ObjCObjectType, { + // We have to watch out here because an ObjCInterfaceType's base + // type is itself. + if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) + TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { + ObjCProtocolLoc ProtocolLoc(TL.getProtocol(I), TL.getProtocolLoc(I)); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } +}) + +DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, + { TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); }) + +DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) + +DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) + +DEF_TRAVERSE_TYPELOC(BitIntType, {}) +DEF_TRAVERSE_TYPELOC(DependentBitIntType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getNumBitsExpr())); +}) + +#undef DEF_TRAVERSE_TYPELOC + +// ----------------- Decl traversal ----------------- +// +// For a Decl, we automate (in the DEF_TRAVERSE_DECL macro) traversing +// the children that come from the DeclContext associated with it. +// Therefore each Traverse* only needs to worry about children other +// than those. + +template +bool RecursiveASTEnterExitVisitor::canIgnoreChildDeclWhileTraversingDeclContext( + const Decl *Child) { + // BlockDecls are traversed through BlockExprs, + // CapturedDecls are traversed through CapturedStmts. + if (isa(Child) || isa(Child)) + return true; + // Lambda classes are traversed through LambdaExprs. + if (const CXXRecordDecl* Cls = dyn_cast(Child)) + return Cls->isLambda(); + return false; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseDeclContextHelper(DeclContext *DC) { + if (!DC) + return true; + + for (auto *Child : DC->decls()) { + if (!canIgnoreChildDeclWhileTraversingDeclContext(Child)) + TRY_TO(TraverseDecl(Child)); + } + + return true; +} + +// This macro makes available a variable D, the passed-in decl. +#define DEF_TRAVERSE_DECL(DECL, CODE) \ + template \ + bool RecursiveASTEnterExitVisitor::Traverse##DECL(DECL *D) { \ + bool ShouldVisitChildren = true; \ + bool ReturnValue = true; \ + if (!getDerived().shouldTraversePostOrder()) \ + TRY_TO(WalkUpFrom##DECL(D)); \ + { CODE; } \ + if (ReturnValue && ShouldVisitChildren) \ + TRY_TO(TraverseDeclContextHelper(dyn_cast(D))); \ + if (ReturnValue) { \ + /* Visit any attributes attached to this declaration. */ \ + for (auto *I : D->attrs()) \ + TRY_TO(getDerived().TraverseAttr(I)); \ + } \ + if (ReturnValue && getDerived().shouldTraversePostOrder()) \ + TRY_TO(WalkUpFrom##DECL(D)); \ + return ReturnValue; \ + } + +DEF_TRAVERSE_DECL(AccessSpecDecl, {}) + +DEF_TRAVERSE_DECL(BlockDecl, { + if (TypeSourceInfo *TInfo = D->getSignatureAsWritten()) + TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc())); + TRY_TO(TraverseStmt(D->getBody())); + for (const auto &I : D->captures()) { + if (I.hasCopyExpr()) { + TRY_TO(TraverseStmt(I.getCopyExpr())); + } + } + ShouldVisitChildren = false; +}) + +DEF_TRAVERSE_DECL(OutlinedFunctionDecl, { + TRY_TO(TraverseStmt(D->getBody())); + ShouldVisitChildren = false; +}) + +DEF_TRAVERSE_DECL(CapturedDecl, { + TRY_TO(TraverseStmt(D->getBody())); + ShouldVisitChildren = false; +}) + +DEF_TRAVERSE_DECL(EmptyDecl, {}) + +DEF_TRAVERSE_DECL(HLSLBufferDecl, {}) + +DEF_TRAVERSE_DECL(LifetimeExtendedTemporaryDecl, { + TRY_TO(TraverseStmt(D->getTemporaryExpr())); +}) + +DEF_TRAVERSE_DECL(FileScopeAsmDecl, + { TRY_TO(TraverseStmt(D->getAsmString())); }) + +DEF_TRAVERSE_DECL(TopLevelStmtDecl, { TRY_TO(TraverseStmt(D->getStmt())); }) + +DEF_TRAVERSE_DECL(ImportDecl, {}) + +DEF_TRAVERSE_DECL(FriendDecl, { + // Friend is either decl or a type. + if (D->getFriendType()) { + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + // Traverse any CXXRecordDecl owned by this type, since + // it will not be in the parent context: + if (auto *ET = D->getFriendType()->getType()->getAs()) + TRY_TO(TraverseDecl(ET->getOwnedTagDecl())); + } else { + TRY_TO(TraverseDecl(D->getFriendDecl())); + } +}) + +DEF_TRAVERSE_DECL(FriendTemplateDecl, { + if (D->getFriendType()) + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + else + TRY_TO(TraverseDecl(D->getFriendDecl())); + for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) { + TemplateParameterList *TPL = D->getTemplateParameterList(I); + for (TemplateParameterList::iterator ITPL = TPL->begin(), ETPL = TPL->end(); + ITPL != ETPL; ++ITPL) { + TRY_TO(TraverseDecl(*ITPL)); + } + } +}) + +DEF_TRAVERSE_DECL(LinkageSpecDecl, {}) + +DEF_TRAVERSE_DECL(ExportDecl, {}) + +DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {// FIXME: implement this + }) + +DEF_TRAVERSE_DECL(StaticAssertDecl, { + TRY_TO(TraverseStmt(D->getAssertExpr())); + TRY_TO(TraverseStmt(D->getMessage())); +}) + +DEF_TRAVERSE_DECL(TranslationUnitDecl, { + // Code in an unnamed namespace shows up automatically in + // decls_begin()/decls_end(). Thus we don't need to recurse on + // D->getAnonymousNamespace(). + + // If the traversal scope is set, then consider them to be the children of + // the TUDecl, rather than traversing (and loading?) all top-level decls. + auto Scope = D->getASTContext().getTraversalScope(); + bool HasLimitedScope = + Scope.size() != 1 || !isa(Scope.front()); + if (HasLimitedScope) { + ShouldVisitChildren = false; // we'll do that here instead + for (auto *Child : Scope) { + if (!canIgnoreChildDeclWhileTraversingDeclContext(Child)) + TRY_TO(TraverseDecl(Child)); + } + } +}) + +DEF_TRAVERSE_DECL(PragmaCommentDecl, {}) + +DEF_TRAVERSE_DECL(PragmaDetectMismatchDecl, {}) + +DEF_TRAVERSE_DECL(ExternCContextDecl, {}) + +DEF_TRAVERSE_DECL(NamespaceAliasDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + + // We shouldn't traverse an aliased namespace, since it will be + // defined (and, therefore, traversed) somewhere else. + ShouldVisitChildren = false; +}) + +DEF_TRAVERSE_DECL(LabelDecl, {// There is no code in a LabelDecl. + }) + +DEF_TRAVERSE_DECL( + NamespaceDecl, + {// Code in an unnamed namespace shows up automatically in + // decls_begin()/decls_end(). Thus we don't need to recurse on + // D->getAnonymousNamespace(). + }) + +DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCCategoryDecl, { + if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } + for (auto It : llvm::zip(D->protocols(), D->protocol_locs())) { + ObjCProtocolLoc ProtocolLoc(std::get<0>(It), std::get<1>(It)); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } +}) + +DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCInterfaceDecl, { + if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) { + for (auto typeParam : *typeParamList) { + TRY_TO(TraverseObjCTypeParamDecl(typeParam)); + } + } + + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); + } + if (D->isThisDeclarationADefinition()) { + for (auto It : llvm::zip(D->protocols(), D->protocol_locs())) { + ObjCProtocolLoc ProtocolLoc(std::get<0>(It), std::get<1>(It)); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } + } +}) + +DEF_TRAVERSE_DECL(ObjCProtocolDecl, { + if (D->isThisDeclarationADefinition()) { + for (auto It : llvm::zip(D->protocols(), D->protocol_locs())) { + ObjCProtocolLoc ProtocolLoc(std::get<0>(It), std::get<1>(It)); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } + } +}) + +DEF_TRAVERSE_DECL(ObjCMethodDecl, { + if (D->getReturnTypeSourceInfo()) { + TRY_TO(TraverseTypeLoc(D->getReturnTypeSourceInfo()->getTypeLoc())); + } + for (ParmVarDecl *Parameter : D->parameters()) { + TRY_TO(TraverseDecl(Parameter)); + } + if (D->isThisDeclarationADefinition()) { + TRY_TO(TraverseStmt(D->getBody())); + } + ShouldVisitChildren = false; +}) + +DEF_TRAVERSE_DECL(ObjCTypeParamDecl, { + if (D->hasExplicitBound()) { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type alias, not something that was written in the + // source. + } +}) + +DEF_TRAVERSE_DECL(ObjCPropertyDecl, { + if (D->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + else + TRY_TO(TraverseType(D->getType())); + ShouldVisitChildren = false; +}) + +DEF_TRAVERSE_DECL(UsingDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); +}) + +DEF_TRAVERSE_DECL(UsingEnumDecl, + { TRY_TO(TraverseTypeLoc(D->getEnumTypeLoc())); }) + +DEF_TRAVERSE_DECL(UsingPackDecl, {}) + +DEF_TRAVERSE_DECL(UsingDirectiveDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); +}) + +DEF_TRAVERSE_DECL(UsingShadowDecl, {}) + +DEF_TRAVERSE_DECL(ConstructorUsingShadowDecl, {}) + +DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, { + for (auto *I : D->varlist()) { + TRY_TO(TraverseStmt(I)); + } +}) + +DEF_TRAVERSE_DECL(OMPRequiresDecl, { + for (auto *C : D->clauselists()) { + TRY_TO(TraverseOMPClause(C)); + } +}) + +DEF_TRAVERSE_DECL(OMPDeclareReductionDecl, { + TRY_TO(TraverseStmt(D->getCombiner())); + if (auto *Initializer = D->getInitializer()) + TRY_TO(TraverseStmt(Initializer)); + TRY_TO(TraverseType(D->getType())); + return true; +}) + +DEF_TRAVERSE_DECL(OMPDeclareMapperDecl, { + for (auto *C : D->clauselists()) + TRY_TO(TraverseOMPClause(C)); + TRY_TO(TraverseType(D->getType())); + return true; +}) + +DEF_TRAVERSE_DECL(OMPCapturedExprDecl, { TRY_TO(TraverseVarHelper(D)); }) + +DEF_TRAVERSE_DECL(OMPAllocateDecl, { + for (auto *I : D->varlist()) + TRY_TO(TraverseStmt(I)); + for (auto *C : D->clauselists()) + TRY_TO(TraverseOMPClause(C)); +}) + +DEF_TRAVERSE_DECL(OpenACCDeclareDecl, + { TRY_TO(VisitOpenACCClauseList(D->clauses())); }) + +DEF_TRAVERSE_DECL(OpenACCRoutineDecl, { + TRY_TO(TraverseStmt(D->getFunctionReference())); + TRY_TO(VisitOpenACCClauseList(D->clauses())); +}) + +// A helper method for TemplateDecl's children. +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateParameterListHelper( + TemplateParameterList *TPL) { + if (TPL) { + for (NamedDecl *D : *TPL) { + TRY_TO(TraverseDecl(D)); + } + if (Expr *RequiresClause = TPL->getRequiresClause()) { + TRY_TO(TraverseStmt(RequiresClause)); + } + } + return true; +} + +template +template +bool RecursiveASTEnterExitVisitor::TraverseDeclTemplateParameterLists(T *D) { + for (unsigned i = 0; i < D->getNumTemplateParameterLists(); i++) { + TemplateParameterList *TPL = D->getTemplateParameterList(i); + TraverseTemplateParameterListHelper(TPL); + } + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateInstantiations( + ClassTemplateDecl *D) { + for (auto *SD : D->specializations()) { + for (auto *RD : SD->redecls()) { + assert(!cast(RD)->isInjectedClassName()); + switch ( + cast(RD)->getSpecializationKind()) { + // Visit the implicit instantiations with the requested pattern. + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + TRY_TO(TraverseDecl(RD)); + break; + + // We don't need to do anything on an explicit instantiation + // or explicit specialization because there will be an explicit + // node for it elsewhere. + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: + break; + } + } + } + + return true; +} + +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateInstantiations( + VarTemplateDecl *D) { + for (auto *SD : D->specializations()) { + for (auto *RD : SD->redecls()) { + switch ( + cast(RD)->getSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + TRY_TO(TraverseDecl(RD)); + break; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: + break; + } + } + } + + return true; +} + +// A helper method for traversing the instantiations of a +// function while skipping its specializations. +template +bool RecursiveASTEnterExitVisitor::TraverseTemplateInstantiations( + FunctionTemplateDecl *D) { + for (auto *FD : D->specializations()) { + for (auto *RD : FD->redecls()) { + switch (RD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // We don't know what kind of FunctionDecl this is. + TRY_TO(TraverseDecl(RD)); + break; + + // FIXME: For now traverse explicit instantiations here. Change that + // once they are represented as dedicated nodes in the AST. + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + TRY_TO(TraverseDecl(RD)); + break; + + case TSK_ExplicitSpecialization: + break; + } + } + } + + return true; +} + +// This macro unifies the traversal of class, variable and function +// template declarations. +#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \ + DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \ + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \ + TRY_TO(TraverseDecl(D->getTemplatedDecl())); \ + \ + /* By default, we do not traverse the instantiations of \ + class templates since they do not appear in the user code. The \ + following code optionally traverses them. \ + \ + We only traverse the class instantiations when we see the canonical \ + declaration of the template, to ensure we only visit them once. */ \ + if (getDerived().shouldVisitTemplateInstantiations() && \ + D == D->getCanonicalDecl()) \ + TRY_TO(TraverseTemplateInstantiations(D)); \ + \ + /* Note that getInstantiatedFromMemberTemplate() is just a link \ + from a template instantiation back to the template from which \ + it was instantiated, and thus should not be traversed. */ \ + }) + +DEF_TRAVERSE_TMPL_DECL(Class) +DEF_TRAVERSE_TMPL_DECL(Var) +DEF_TRAVERSE_TMPL_DECL(Function) + +DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, { + // D is the "T" in something like + // template