diff --git a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h new file mode 100644 index 000000000000..4382d2099082 --- /dev/null +++ b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h @@ -0,0 +1,276 @@ +//===--- DynamicRecursiveASTVisitor.h - Virtual 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 DynamicRecursiveASTVisitor interface, which acts +// identically to RecursiveASTVisitor, except that it uses virtual dispatch +// instead of CRTP, which greatly improves compile times and binary size. +// +// Prefer to use this over RecursiveASTVisitor whenever possible. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H +#define LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H + +#include "clang/AST/Attr.h" +#include "clang/AST/ExprConcepts.h" +#include "clang/AST/TypeLoc.h" + +namespace clang { +class ASTContext; + +/// Recursive AST visitor that supports extension via dynamic dispatch. +/// +/// Like RecursiveASTVisitor, this class allows for traversal of arbitrarily +/// complex ASTs. The main difference is that this uses virtual functions +/// instead of CRTP, which greatly improves compile times of Clang itself, +/// as well as binary size. +/// +/// Instead of functions (e.g. shouldVisitImplicitCode()), this class +/// uses member variables (e.g. ShouldVisitImplicitCode) to control +/// visitation behaviour. +/// +/// However, there is no support for overriding some of the less commonly +/// used features of the RAV, such as WalkUpFromX or attribute traversal +/// (attributes can still be traversed, but you can't change what happens +/// when we traverse one). +/// +/// The following is a list of RAV features that are NOT customisable: +/// +/// - Visiting attributes, +/// - Overriding WalkUpFromX, +/// - Overriding getStmtChildren(). +/// +/// Furthermore, post-order traversal is not supported at all. +/// +/// Prefer to use this over RecursiveASTVisitor unless you absolutely +/// need to use one of the features listed above (e.g. overriding +/// WalkUpFromX or post-order traversal). +/// +/// \see RecursiveASTVisitor. +class DynamicRecursiveASTVisitor { +public: + /// Whether this visitor should recurse into template instantiations. + bool ShouldVisitTemplateInstantiations = false; + + /// Whether this visitor should recurse into the types of TypeLocs. + bool ShouldWalkTypesOfTypeLocs = true; + + /// Whether this visitor should recurse into implicit code, e.g. + /// implicit constructors and destructors. + bool ShouldVisitImplicitCode = false; + + /// Whether this visitor should recurse into lambda body. + bool ShouldVisitLambdaBody = true; + +protected: + DynamicRecursiveASTVisitor() = default; + DynamicRecursiveASTVisitor(DynamicRecursiveASTVisitor &&) = default; + DynamicRecursiveASTVisitor(const DynamicRecursiveASTVisitor &) = default; + DynamicRecursiveASTVisitor & + operator=(DynamicRecursiveASTVisitor &&) = default; + DynamicRecursiveASTVisitor & + operator=(const DynamicRecursiveASTVisitor &) = default; + +public: + virtual void anchor(); + virtual ~DynamicRecursiveASTVisitor() = default; + + /// Recursively visits an entire AST, starting from the TranslationUnitDecl. + /// \returns false if visitation was terminated early. + virtual bool TraverseAST(ASTContext &AST); + + /// 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). + virtual bool TraverseAttr(Attr *At); + + /// 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. + virtual bool TraverseConstructorInitializer(CXXCtorInitializer *Init); + + /// Recursively visit a base specifier. This can be overridden by a + /// subclass. + /// + /// \returns false if the visitation was terminated early, true otherwise. + virtual bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base); + + /// 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). + virtual bool TraverseDecl(Decl *D); + + /// Recursively visit a name with its location information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + virtual bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo); + + /// 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. + virtual bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, + Expr *Init); + + /// Recursively visit a C++ nested-name-specifier. + /// + /// \returns false if the visitation was terminated early, true otherwise. + virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// Recursively visit a C++ nested-name-specifier with location + /// information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + virtual bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); + + /// 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). + virtual bool TraverseStmt(Stmt *S); + + /// 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. + virtual 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. + virtual bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc); + + /// Recursively visit a set of template arguments. + /// + /// \returns false if the visitation was terminated early, true otherwise. + // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead. + // Not virtual for now because no-one overrides it. + bool TraverseTemplateArguments(ArrayRef Args); + + /// Recursively visit a template name and dispatch to the + /// appropriate method. + /// + /// \returns false if the visitation was terminated early, true otherwise. + virtual bool TraverseTemplateName(TemplateName Template); + + /// 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). + virtual 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). + virtual bool TraverseTypeLoc(TypeLoc TL); + + /// Recursively visit an Objective-C protocol reference with location + /// information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + virtual bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc); + + /// Traverse a concept (requirement). + virtual bool TraverseTypeConstraint(const TypeConstraint *C); + virtual bool TraverseConceptRequirement(concepts::Requirement *R); + virtual bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R); + virtual bool TraverseConceptExprRequirement(concepts::ExprRequirement *R); + virtual bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R); + virtual bool TraverseConceptReference(ConceptReference *CR); + virtual bool VisitConceptReference(ConceptReference *CR) { return true; } + + /// Visit a node. + virtual bool VisitAttr(Attr *A) { return true; } + virtual bool VisitDecl(Decl *D) { return true; } + virtual bool VisitStmt(Stmt *S) { return true; } + virtual bool VisitType(Type *T) { return true; } + virtual bool VisitTypeLoc(TypeLoc TL) { return true; } + + /// Walk up from a node. + bool WalkUpFromDecl(Decl *D) { return VisitDecl(D); } + bool WalkUpFromStmt(Stmt *S) { return VisitStmt(S); } + bool WalkUpFromType(Type *T) { return VisitType(T); } + bool WalkUpFromTypeLoc(TypeLoc TL) { return VisitTypeLoc(TL); } + + /// Invoked before visiting a statement or expression via data recursion. + /// + /// \returns false to skip visiting the node, true otherwise. + virtual 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. + virtual bool dataTraverseStmtPost(Stmt *S) { return true; } + virtual bool dataTraverseNode(Stmt *S); + +#define DEF_TRAVERSE_TMPL_INST(kind) \ + virtual bool TraverseTemplateInstantiations(kind##TemplateDecl *D); + DEF_TRAVERSE_TMPL_INST(Class) + DEF_TRAVERSE_TMPL_INST(Var) + DEF_TRAVERSE_TMPL_INST(Function) +#undef DEF_TRAVERSE_TMPL_INST + + // Decls. +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) virtual bool Traverse##CLASS##Decl(CLASS##Decl *D); +#include "clang/AST/DeclNodes.inc" + +#define DECL(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D); \ + virtual bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; } +#include "clang/AST/DeclNodes.inc" + + // Stmts. +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) virtual bool Traverse##CLASS(CLASS *S); +#include "clang/AST/StmtNodes.inc" + +#define STMT(CLASS, PARENT) \ + bool WalkUpFrom##CLASS(CLASS *S); \ + virtual bool Visit##CLASS(CLASS *S) { return true; } +#include "clang/AST/StmtNodes.inc" + + // Types. +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) virtual bool Traverse##CLASS##Type(CLASS##Type *T); +#include "clang/AST/TypeNodes.inc" + +#define TYPE(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Type(CLASS##Type *T); \ + virtual bool Visit##CLASS##Type(CLASS##Type *T) { return true; } +#include "clang/AST/TypeNodes.inc" + + // TypeLocs. +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) \ + virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); +#include "clang/AST/TypeLocNodes.def" + +#define TYPELOC(CLASS, BASE) \ + bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL); \ + virtual bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; } +#include "clang/AST/TypeLocNodes.def" +}; +} // namespace clang + +#endif // LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 038856248c16..52c6a45de9a2 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -53,6 +53,7 @@ add_clang_library(clangAST DeclOpenMP.cpp DeclPrinter.cpp DeclTemplate.cpp + DynamicRecursiveASTVisitor.cpp ParentMapContext.cpp Expr.cpp ExprClassification.cpp diff --git a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp new file mode 100644 index 000000000000..8cfabd9f3e93 --- /dev/null +++ b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp @@ -0,0 +1,452 @@ +//=== DynamicRecursiveASTVisitor.cpp - Dynamic AST Visitor Implementation -===// +// +// 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 implements DynamicRecursiveASTVisitor in terms of the CRTP-based +// RecursiveASTVisitor. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/DynamicRecursiveASTVisitor.h" +#include "clang/AST/RecursiveASTVisitor.h" + +using namespace clang; + +// The implementation of DRAV deserves some explanation: +// +// We want to implement DynamicRecursiveASTVisitor without having to inherit or +// reference RecursiveASTVisitor in any way in the header: if we instantiate +// RAV in the header, then every user of (or rather every file that uses) DRAV +// still has to instantiate a RAV, which gets us nowhere. Moreover, even just +// including RecursiveASTVisitor.h would probably cause some amount of slowdown +// because we'd have to parse a huge template. For these reasons, the fact that +// DRAV is implemented using a RAV is solely an implementation detail. +// +// As for the implementation itself, DRAV by default acts exactly like a RAV +// that overrides none of RAV's functions. There are two parts to this: +// +// 1. Any function in DRAV has to act like the corresponding function in RAV, +// unless overridden by a derived class, of course. +// +// 2. Any call to a function by the RAV implementation that DRAV allows to be +// overridden must be transformed to a virtual call on the user-provided +// DRAV object: if some function in RAV calls e.g. TraverseCallExpr() +// during traversal, then the derived class's TraverseCallExpr() must be +// called (provided it overrides TraverseCallExpr()). +// +// The 'Impl' class is a helper that connects the two implementations; it is +// a wrapper around a reference to a DRAV that is itself a RecursiveASTVisitor. +// It overrides every function in RAV *that is virtual in DRAV* to perform a +// virtual call on its DRAV reference. This accomplishes point 2 above. +// +// Point 1 is accomplished by, first, having the base class implementation of +// each of the virtual functions construct an Impl object (which is actually +// just a no-op), passing in itself so that any virtual calls use the right +// vtable. Secondly, it then calls RAV's implementation of that same function +// *on Impl* (using a qualified call so that we actually call into the RAV +// implementation instead of Impl's version of that same function); this way, +// we both execute RAV's implementation for this function only and ensure that +// calls to subsequent functions call into Impl via CRTP (and Impl then calls +// back into DRAV and so on). +// +// While this ends up constructing a lot of Impl instances (almost one per +// function call), this doesn't really matter since Impl just holds a single +// pointer, and everything in this file should get inlined into all the DRAV +// functions here anyway. +// +//===----------------------------------------------------------------------===// +// +// The following illustrates how a call to an (overridden) function is actually +// resolved: given some class 'Derived' that derives from DRAV and overrides +// TraverseStmt(), if we are traversing some AST, and TraverseStmt() is called +// by the RAV implementation, the following happens: +// +// 1. Impl::TraverseStmt() overrides RAV::TraverseStmt() via CRTP, so the +// former is called. +// +// 2. Impl::TraverseStmt() performs a virtual call to the visitor (which is +// an instance to Derived), so Derived::TraverseStmt() is called. +// +// End result: Derived::TraverseStmt() is executed. +// +// Suppose some other function, e.g. TraverseCallExpr(), which is NOT overridden +// by Derived is called, we get: +// +// 1. Impl::TraverseCallExpr() overrides RAV::TraverseCallExpr() via CRTP, +// so the former is called. +// +// 2. Impl::TraverseCallExpr() performs a virtual call, but since Derived +// does not override that function, DRAV::TraverseCallExpr() is called. +// +// 3. DRAV::TraverseCallExpr() creates a new instance of Impl, passing in +// itself (this doesn't change that the pointer is an instance of Derived); +// it then calls RAV::TraverseCallExpr() on the Impl object, which actually +// ends up executing RAV's implementation because we used a qualified +// function call. +// +// End result: RAV::TraverseCallExpr() is executed, +namespace { +struct Impl : RecursiveASTVisitor { + DynamicRecursiveASTVisitor &Visitor; + Impl(DynamicRecursiveASTVisitor &Visitor) : Visitor(Visitor) {} + + bool shouldVisitTemplateInstantiations() const { + return Visitor.ShouldVisitTemplateInstantiations; + } + + bool shouldWalkTypesOfTypeLocs() const { + return Visitor.ShouldWalkTypesOfTypeLocs; + } + + bool shouldVisitImplicitCode() const { + return Visitor.ShouldVisitImplicitCode; + } + + bool shouldVisitLambdaBody() const { return Visitor.ShouldVisitLambdaBody; } + + // Supporting post-order would be very hard because of quirks of the + // RAV implementation that only work with CRTP. It also is only used + // by less than 5 visitors in the entire code base. + bool shouldTraversePostOrder() const { return false; } + + bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); } + bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); } + bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); } + bool TraverseType(QualType T) { return Visitor.TraverseType(T); } + bool TraverseTypeLoc(TypeLoc TL) { return Visitor.TraverseTypeLoc(TL); } + bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); } + + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + return Visitor.TraverseConstructorInitializer(Init); + } + + bool TraverseTemplateArgument(const TemplateArgument &Arg) { + return Visitor.TraverseTemplateArgument(Arg); + } + + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { + return Visitor.TraverseTemplateArgumentLoc(ArgLoc); + } + + bool TraverseTemplateName(TemplateName Template) { + return Visitor.TraverseTemplateName(Template); + } + + bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) { + return Visitor.TraverseObjCProtocolLoc(ProtocolLoc); + } + + bool TraverseTypeConstraint(const TypeConstraint *C) { + return Visitor.TraverseTypeConstraint(C); + } + bool TraverseConceptRequirement(concepts::Requirement *R) { + return Visitor.TraverseConceptRequirement(R); + } + bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R) { + return Visitor.TraverseConceptTypeRequirement(R); + } + bool TraverseConceptExprRequirement(concepts::ExprRequirement *R) { + return Visitor.TraverseConceptExprRequirement(R); + } + bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R) { + return Visitor.TraverseConceptNestedRequirement(R); + } + + bool TraverseConceptReference(ConceptReference *CR) { + return Visitor.TraverseConceptReference(CR); + } + + bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) { + return Visitor.TraverseCXXBaseSpecifier(Base); + } + + bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) { + return Visitor.TraverseDeclarationNameInfo(NameInfo); + } + + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, + Expr *Init) { + return Visitor.TraverseLambdaCapture(LE, C, Init); + } + + bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { + return Visitor.TraverseNestedNameSpecifier(NNS); + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + return Visitor.TraverseNestedNameSpecifierLoc(NNS); + } + + bool VisitConceptReference(ConceptReference *CR) { + return Visitor.VisitConceptReference(CR); + } + + bool dataTraverseStmtPre(Stmt *S) { return Visitor.dataTraverseStmtPre(S); } + bool dataTraverseStmtPost(Stmt *S) { return Visitor.dataTraverseStmtPost(S); } + + // TraverseStmt() always passes in a queue, so we have no choice but to + // accept it as a parameter here. + bool dataTraverseNode(Stmt *S, DataRecursionQueue * = nullptr) { + // But since don't support postorder traversal, we don't need it, so + // simply discard it here. This way, derived classes don't need to worry + // about including it as a parameter that they never use. + return Visitor.dataTraverseNode(S); + } + + /// Visit a node. + bool VisitAttr(Attr *A) { return Visitor.VisitAttr(A); } + bool VisitDecl(Decl *D) { return Visitor.VisitDecl(D); } + bool VisitStmt(Stmt *S) { return Visitor.VisitStmt(S); } + bool VisitType(Type *T) { return Visitor.VisitType(T); } + bool VisitTypeLoc(TypeLoc TL) { return Visitor.VisitTypeLoc(TL); } + +#define DEF_TRAVERSE_TMPL_INST(kind) \ + bool TraverseTemplateInstantiations(kind##TemplateDecl *D) { \ + return Visitor.TraverseTemplateInstantiations(D); \ + } + DEF_TRAVERSE_TMPL_INST(Class) + DEF_TRAVERSE_TMPL_INST(Var) + DEF_TRAVERSE_TMPL_INST(Function) +#undef DEF_TRAVERSE_TMPL_INST + + // Decls. +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) \ + bool Traverse##CLASS##Decl(CLASS##Decl *D) { \ + return Visitor.Traverse##CLASS##Decl(D); \ + } +#include "clang/AST/DeclNodes.inc" + +#define DECL(CLASS, BASE) \ + bool Visit##CLASS##Decl(CLASS##Decl *D) { \ + return Visitor.Visit##CLASS##Decl(D); \ + } +#include "clang/AST/DeclNodes.inc" + + // Stmts. +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + bool Traverse##CLASS(CLASS *S) { return Visitor.Traverse##CLASS(S); } +#include "clang/AST/StmtNodes.inc" + +#define STMT(CLASS, PARENT) \ + bool Visit##CLASS(CLASS *S) { return Visitor.Visit##CLASS(S); } +#include "clang/AST/StmtNodes.inc" + + // Types. +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) \ + bool Traverse##CLASS##Type(CLASS##Type *T) { \ + return Visitor.Traverse##CLASS##Type(T); \ + } +#include "clang/AST/TypeNodes.inc" + +#define TYPE(CLASS, BASE) \ + bool Visit##CLASS##Type(CLASS##Type *T) { \ + return Visitor.Visit##CLASS##Type(T); \ + } +#include "clang/AST/TypeNodes.inc" + + // TypeLocs. +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) \ + bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ + return Visitor.Traverse##CLASS##TypeLoc(TL); \ + } +#include "clang/AST/TypeLocNodes.def" + +#define TYPELOC(CLASS, BASE) \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ + return Visitor.Visit##CLASS##TypeLoc(TL); \ + } +#include "clang/AST/TypeLocNodes.def" +}; +} // namespace + +void DynamicRecursiveASTVisitor::anchor() {} + +bool DynamicRecursiveASTVisitor::TraverseAST(ASTContext &AST) { + return Impl(*this).RecursiveASTVisitor::TraverseAST(AST); +} + +bool DynamicRecursiveASTVisitor::TraverseAttr(Attr *At) { + return Impl(*this).RecursiveASTVisitor::TraverseAttr(At); +} + +bool DynamicRecursiveASTVisitor::TraverseConstructorInitializer( + CXXCtorInitializer *Init) { + return Impl(*this).RecursiveASTVisitor::TraverseConstructorInitializer( + Init); +} + +bool DynamicRecursiveASTVisitor::TraverseDecl(Decl *D) { + return Impl(*this).RecursiveASTVisitor::TraverseDecl(D); +} + +bool DynamicRecursiveASTVisitor::TraverseLambdaCapture(LambdaExpr *LE, + const LambdaCapture *C, + Expr *Init) { + return Impl(*this).RecursiveASTVisitor::TraverseLambdaCapture(LE, C, + Init); +} + +bool DynamicRecursiveASTVisitor::TraverseStmt(Stmt *S) { + return Impl(*this).RecursiveASTVisitor::TraverseStmt(S); +} + +bool DynamicRecursiveASTVisitor::TraverseTemplateArgument( + const TemplateArgument &Arg) { + return Impl(*this).RecursiveASTVisitor::TraverseTemplateArgument(Arg); +} + +bool DynamicRecursiveASTVisitor::TraverseTemplateArguments( + ArrayRef Args) { + return Impl(*this).RecursiveASTVisitor::TraverseTemplateArguments(Args); +} + +bool DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc( + const TemplateArgumentLoc &ArgLoc) { + return Impl(*this).RecursiveASTVisitor::TraverseTemplateArgumentLoc( + ArgLoc); +} + +bool DynamicRecursiveASTVisitor::TraverseTemplateName(TemplateName Template) { + return Impl(*this).RecursiveASTVisitor::TraverseTemplateName(Template); +} + +bool DynamicRecursiveASTVisitor::TraverseType(QualType T) { + return Impl(*this).RecursiveASTVisitor::TraverseType(T); +} + +bool DynamicRecursiveASTVisitor::TraverseTypeLoc(TypeLoc TL) { + return Impl(*this).RecursiveASTVisitor::TraverseTypeLoc(TL); +} + +bool DynamicRecursiveASTVisitor::TraverseTypeConstraint( + const TypeConstraint *C) { + return Impl(*this).RecursiveASTVisitor::TraverseTypeConstraint(C); +} +bool DynamicRecursiveASTVisitor::TraverseObjCProtocolLoc( + ObjCProtocolLoc ProtocolLoc) { + return Impl(*this).RecursiveASTVisitor::TraverseObjCProtocolLoc( + ProtocolLoc); +} + +bool DynamicRecursiveASTVisitor::TraverseConceptRequirement( + concepts::Requirement *R) { + return Impl(*this).RecursiveASTVisitor::TraverseConceptRequirement(R); +} +bool DynamicRecursiveASTVisitor::TraverseConceptTypeRequirement( + concepts::TypeRequirement *R) { + return Impl(*this).RecursiveASTVisitor::TraverseConceptTypeRequirement( + R); +} +bool DynamicRecursiveASTVisitor::TraverseConceptExprRequirement( + concepts::ExprRequirement *R) { + return Impl(*this).RecursiveASTVisitor::TraverseConceptExprRequirement( + R); +} +bool DynamicRecursiveASTVisitor::TraverseConceptNestedRequirement( + concepts::NestedRequirement *R) { + return Impl(*this) + .RecursiveASTVisitor::TraverseConceptNestedRequirement(R); +} + +bool DynamicRecursiveASTVisitor::TraverseConceptReference( + ConceptReference *CR) { + return Impl(*this).RecursiveASTVisitor::TraverseConceptReference(CR); +} + +bool DynamicRecursiveASTVisitor::TraverseCXXBaseSpecifier( + const CXXBaseSpecifier &Base) { + return Impl(*this).RecursiveASTVisitor::TraverseCXXBaseSpecifier(Base); +} + +bool DynamicRecursiveASTVisitor::TraverseDeclarationNameInfo( + DeclarationNameInfo NameInfo) { + return Impl(*this).RecursiveASTVisitor::TraverseDeclarationNameInfo( + NameInfo); +} + +bool DynamicRecursiveASTVisitor::TraverseNestedNameSpecifier( + NestedNameSpecifier *NNS) { + return Impl(*this).RecursiveASTVisitor::TraverseNestedNameSpecifier( + NNS); +} + +bool DynamicRecursiveASTVisitor::TraverseNestedNameSpecifierLoc( + NestedNameSpecifierLoc NNS) { + return Impl(*this).RecursiveASTVisitor::TraverseNestedNameSpecifierLoc( + NNS); +} + +bool DynamicRecursiveASTVisitor::dataTraverseNode(Stmt *S) { + return Impl(*this).RecursiveASTVisitor::dataTraverseNode(S, nullptr); +} + +#define DEF_TRAVERSE_TMPL_INST(kind) \ + bool DynamicRecursiveASTVisitor::TraverseTemplateInstantiations( \ + kind##TemplateDecl *D) { \ + return Impl(*this) \ + .RecursiveASTVisitor::TraverseTemplateInstantiations(D); \ + } +DEF_TRAVERSE_TMPL_INST(Class) +DEF_TRAVERSE_TMPL_INST(Var) +DEF_TRAVERSE_TMPL_INST(Function) +#undef DEF_TRAVERSE_TMPL_INST + +// Declare Traverse*() for and friends all concrete Decl classes. +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) \ + bool DynamicRecursiveASTVisitor::Traverse##CLASS##Decl(CLASS##Decl *D) { \ + return Impl(*this).RecursiveASTVisitor::Traverse##CLASS##Decl(D); \ + } \ + bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \ + return Impl(*this).RecursiveASTVisitor::WalkUpFrom##CLASS##Decl(D); \ + } +#include "clang/AST/DeclNodes.inc" + +// Declare Traverse*() and friends for all concrete Stmt classes. +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + bool DynamicRecursiveASTVisitor::Traverse##CLASS(CLASS *S) { \ + return Impl(*this).RecursiveASTVisitor::Traverse##CLASS(S); \ + } +#include "clang/AST/StmtNodes.inc" + +#define STMT(CLASS, PARENT) \ + bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS(CLASS *S) { \ + return Impl(*this).RecursiveASTVisitor::WalkUpFrom##CLASS(S); \ + } +#include "clang/AST/StmtNodes.inc" + +// Declare Traverse*() and friends for all concrete Typeclasses. +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) \ + bool DynamicRecursiveASTVisitor::Traverse##CLASS##Type(CLASS##Type *T) { \ + return Impl(*this).RecursiveASTVisitor::Traverse##CLASS##Type(T); \ + } \ + bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS##Type(CLASS##Type *T) { \ + return Impl(*this).RecursiveASTVisitor::WalkUpFrom##CLASS##Type(T); \ + } +#include "clang/AST/TypeNodes.inc" + +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) \ + bool DynamicRecursiveASTVisitor::Traverse##CLASS##TypeLoc( \ + CLASS##TypeLoc TL) { \ + return Impl(*this).RecursiveASTVisitor::Traverse##CLASS##TypeLoc( \ + TL); \ + } +#include "clang/AST/TypeLocNodes.def" + +#define TYPELOC(CLASS, BASE) \ + bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS##TypeLoc( \ + CLASS##TypeLoc TL) { \ + return Impl(*this).RecursiveASTVisitor::WalkUpFrom##CLASS##TypeLoc( \ + TL); \ + } +#include "clang/AST/TypeLocNodes.def"