//=== 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"