Path: blob/main/contrib/llvm-project/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
213766 views
//=== DynamicRecursiveASTVisitor.cpp - Dynamic AST Visitor Implementation -===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements DynamicRecursiveASTVisitor in terms of the CRTP-based9// RecursiveASTVisitor.10//11//===----------------------------------------------------------------------===//12#include "clang/AST/DynamicRecursiveASTVisitor.h"13#include "clang/AST/RecursiveASTVisitor.h"1415using namespace clang;1617// The implementation of DRAV deserves some explanation:18//19// We want to implement DynamicRecursiveASTVisitor without having to inherit or20// reference RecursiveASTVisitor in any way in the header: if we instantiate21// RAV in the header, then every user of (or rather every file that uses) DRAV22// still has to instantiate a RAV, which gets us nowhere. Moreover, even just23// including RecursiveASTVisitor.h would probably cause some amount of slowdown24// because we'd have to parse a huge template. For these reasons, the fact that25// DRAV is implemented using a RAV is solely an implementation detail.26//27// As for the implementation itself, DRAV by default acts exactly like a RAV28// that overrides none of RAV's functions. There are two parts to this:29//30// 1. Any function in DRAV has to act like the corresponding function in RAV,31// unless overridden by a derived class, of course.32//33// 2. Any call to a function by the RAV implementation that DRAV allows to be34// overridden must be transformed to a virtual call on the user-provided35// DRAV object: if some function in RAV calls e.g. TraverseCallExpr()36// during traversal, then the derived class's TraverseCallExpr() must be37// called (provided it overrides TraverseCallExpr()).38//39// The 'Impl' class is a helper that connects the two implementations; it is40// a wrapper around a reference to a DRAV that is itself a RecursiveASTVisitor.41// It overrides every function in RAV *that is virtual in DRAV* to perform a42// virtual call on its DRAV reference. This accomplishes point 2 above.43//44// Point 1 is accomplished by, first, having the base class implementation of45// each of the virtual functions construct an Impl object (which is actually46// just a no-op), passing in itself so that any virtual calls use the right47// vtable. Secondly, it then calls RAV's implementation of that same function48// *on Impl* (using a qualified call so that we actually call into the RAV49// implementation instead of Impl's version of that same function); this way,50// we both execute RAV's implementation for this function only and ensure that51// calls to subsequent functions call into Impl via CRTP (and Impl then calls52// back into DRAV and so on).53//54// While this ends up constructing a lot of Impl instances (almost one per55// function call), this doesn't really matter since Impl just holds a single56// pointer, and everything in this file should get inlined into all the DRAV57// functions here anyway.58//59//===----------------------------------------------------------------------===//60//61// The following illustrates how a call to an (overridden) function is actually62// resolved: given some class 'Derived' that derives from DRAV and overrides63// TraverseStmt(), if we are traversing some AST, and TraverseStmt() is called64// by the RAV implementation, the following happens:65//66// 1. Impl::TraverseStmt() overrides RAV::TraverseStmt() via CRTP, so the67// former is called.68//69// 2. Impl::TraverseStmt() performs a virtual call to the visitor (which is70// an instance to Derived), so Derived::TraverseStmt() is called.71//72// End result: Derived::TraverseStmt() is executed.73//74// Suppose some other function, e.g. TraverseCallExpr(), which is NOT overridden75// by Derived is called, we get:76//77// 1. Impl::TraverseCallExpr() overrides RAV::TraverseCallExpr() via CRTP,78// so the former is called.79//80// 2. Impl::TraverseCallExpr() performs a virtual call, but since Derived81// does not override that function, DRAV::TraverseCallExpr() is called.82//83// 3. DRAV::TraverseCallExpr() creates a new instance of Impl, passing in84// itself (this doesn't change that the pointer is an instance of Derived);85// it then calls RAV::TraverseCallExpr() on the Impl object, which actually86// ends up executing RAV's implementation because we used a qualified87// function call.88//89// End result: RAV::TraverseCallExpr() is executed,90namespace {91template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {92DynamicRecursiveASTVisitorBase<Const> &Visitor;93Impl(DynamicRecursiveASTVisitorBase<Const> &Visitor) : Visitor(Visitor) {}9495bool shouldVisitTemplateInstantiations() const {96return Visitor.ShouldVisitTemplateInstantiations;97}9899bool shouldWalkTypesOfTypeLocs() const {100return Visitor.ShouldWalkTypesOfTypeLocs;101}102103bool shouldVisitImplicitCode() const {104return Visitor.ShouldVisitImplicitCode;105}106107bool shouldVisitLambdaBody() const { return Visitor.ShouldVisitLambdaBody; }108109// Supporting post-order would be very hard because of quirks of the110// RAV implementation that only work with CRTP. It also is only used111// by less than 5 visitors in the entire code base.112bool shouldTraversePostOrder() const { return false; }113114bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); }115bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); }116bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); }117bool TraverseType(QualType T) { return Visitor.TraverseType(T); }118bool TraverseTypeLoc(TypeLoc TL) { return Visitor.TraverseTypeLoc(TL); }119bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); }120121bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {122return Visitor.TraverseConstructorInitializer(Init);123}124125bool TraverseTemplateArgument(const TemplateArgument &Arg) {126return Visitor.TraverseTemplateArgument(Arg);127}128129bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {130return Visitor.TraverseTemplateArgumentLoc(ArgLoc);131}132133bool TraverseTemplateName(TemplateName Template) {134return Visitor.TraverseTemplateName(Template);135}136137bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) {138return Visitor.TraverseObjCProtocolLoc(ProtocolLoc);139}140141bool TraverseTypeConstraint(const TypeConstraint *C) {142return Visitor.TraverseTypeConstraint(C);143}144bool TraverseConceptRequirement(concepts::Requirement *R) {145return Visitor.TraverseConceptRequirement(R);146}147bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R) {148return Visitor.TraverseConceptTypeRequirement(R);149}150bool TraverseConceptExprRequirement(concepts::ExprRequirement *R) {151return Visitor.TraverseConceptExprRequirement(R);152}153bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R) {154return Visitor.TraverseConceptNestedRequirement(R);155}156157bool TraverseConceptReference(ConceptReference *CR) {158return Visitor.TraverseConceptReference(CR);159}160161bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {162return Visitor.TraverseCXXBaseSpecifier(Base);163}164165bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {166return Visitor.TraverseDeclarationNameInfo(NameInfo);167}168169bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,170Expr *Init) {171return Visitor.TraverseLambdaCapture(LE, C, Init);172}173174bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {175return Visitor.TraverseNestedNameSpecifier(NNS);176}177178bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {179return Visitor.TraverseNestedNameSpecifierLoc(NNS);180}181182bool VisitConceptReference(ConceptReference *CR) {183return Visitor.VisitConceptReference(CR);184}185186bool dataTraverseStmtPre(Stmt *S) { return Visitor.dataTraverseStmtPre(S); }187bool dataTraverseStmtPost(Stmt *S) { return Visitor.dataTraverseStmtPost(S); }188189// TraverseStmt() always passes in a queue, so we have no choice but to190// accept it as a parameter here.191bool dataTraverseNode(192Stmt *S,193typename RecursiveASTVisitor<Impl>::DataRecursionQueue * = nullptr) {194// But since we don't support postorder traversal, we don't need it, so195// simply discard it here. This way, derived classes don't need to worry196// about including it as a parameter that they never use.197return Visitor.dataTraverseNode(S);198}199200/// Visit a node.201bool VisitAttr(Attr *A) { return Visitor.VisitAttr(A); }202bool VisitDecl(Decl *D) { return Visitor.VisitDecl(D); }203bool VisitStmt(Stmt *S) { return Visitor.VisitStmt(S); }204bool VisitType(Type *T) { return Visitor.VisitType(T); }205bool VisitTypeLoc(TypeLoc TL) { return Visitor.VisitTypeLoc(TL); }206207#define DEF_TRAVERSE_TMPL_INST(kind) \208bool TraverseTemplateInstantiations(kind##TemplateDecl *D) { \209return Visitor.TraverseTemplateInstantiations(D); \210}211DEF_TRAVERSE_TMPL_INST(Class)212DEF_TRAVERSE_TMPL_INST(Var)213DEF_TRAVERSE_TMPL_INST(Function)214#undef DEF_TRAVERSE_TMPL_INST215216// Decls.217#define ABSTRACT_DECL(DECL)218#define DECL(CLASS, BASE) \219bool Traverse##CLASS##Decl(CLASS##Decl *D) { \220return Visitor.Traverse##CLASS##Decl(D); \221}222#include "clang/AST/DeclNodes.inc"223224#define DECL(CLASS, BASE) \225bool Visit##CLASS##Decl(CLASS##Decl *D) { \226return Visitor.Visit##CLASS##Decl(D); \227}228#include "clang/AST/DeclNodes.inc"229230// Stmts.231#define ABSTRACT_STMT(STMT)232#define STMT(CLASS, PARENT) \233bool Traverse##CLASS(CLASS *S) { return Visitor.Traverse##CLASS(S); }234#include "clang/AST/StmtNodes.inc"235236#define STMT(CLASS, PARENT) \237bool Visit##CLASS(CLASS *S) { return Visitor.Visit##CLASS(S); }238#include "clang/AST/StmtNodes.inc"239240// Types.241#define ABSTRACT_TYPE(CLASS, BASE)242#define TYPE(CLASS, BASE) \243bool Traverse##CLASS##Type(CLASS##Type *T) { \244return Visitor.Traverse##CLASS##Type(T); \245}246#include "clang/AST/TypeNodes.inc"247248#define TYPE(CLASS, BASE) \249bool Visit##CLASS##Type(CLASS##Type *T) { \250return Visitor.Visit##CLASS##Type(T); \251}252#include "clang/AST/TypeNodes.inc"253254// TypeLocs.255#define ABSTRACT_TYPELOC(CLASS, BASE)256#define TYPELOC(CLASS, BASE) \257bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL) { \258return Visitor.Traverse##CLASS##TypeLoc(TL); \259}260#include "clang/AST/TypeLocNodes.def"261262#define TYPELOC(CLASS, BASE) \263bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \264return Visitor.Visit##CLASS##TypeLoc(TL); \265}266#include "clang/AST/TypeLocNodes.def"267};268} // namespace269270template <bool Const> void DynamicRecursiveASTVisitorBase<Const>::anchor() {}271272// Helper macros to forward a call to the base implementation since that273// ends up getting very verbose otherwise.274275// This calls the RecursiveASTVisitor implementation of the same function,276// stripping any 'const' that the DRAV implementation may have added since277// the RAV implementation largely doesn't use 'const'.278#define FORWARD_TO_BASE(Function, Type, RefOrPointer) \279template <bool Const> \280bool DynamicRecursiveASTVisitorBase<Const>::Function( \281MaybeConst<Type> RefOrPointer Param) { \282return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function( \283const_cast<Type RefOrPointer>(Param)); \284}285286// Same as 'FORWARD_TO_BASE', but doesn't change the parameter type in any way.287#define FORWARD_TO_BASE_EXACT(Function, Type) \288template <bool Const> \289bool DynamicRecursiveASTVisitorBase<Const>::Function(Type Param) { \290return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function( \291Param); \292}293294FORWARD_TO_BASE(TraverseAST, ASTContext, &)295FORWARD_TO_BASE(TraverseAttr, Attr, *)296FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *)297FORWARD_TO_BASE(TraverseDecl, Decl, *)298FORWARD_TO_BASE(TraverseStmt, Stmt, *)299FORWARD_TO_BASE(TraverseNestedNameSpecifier, NestedNameSpecifier, *)300FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *)301FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *)302FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *)303FORWARD_TO_BASE(TraverseConceptRequirement, concepts::Requirement, *)304FORWARD_TO_BASE(TraverseConceptTypeRequirement, concepts::TypeRequirement, *)305FORWARD_TO_BASE(TraverseConceptExprRequirement, concepts::ExprRequirement, *)306FORWARD_TO_BASE(TraverseConceptReference, ConceptReference, *)307FORWARD_TO_BASE(TraverseConceptNestedRequirement,308concepts::NestedRequirement, *)309310FORWARD_TO_BASE_EXACT(TraverseCXXBaseSpecifier, const CXXBaseSpecifier &)311FORWARD_TO_BASE_EXACT(TraverseDeclarationNameInfo, DeclarationNameInfo)312FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &)313FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef<TemplateArgument>)314FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &)315FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName)316FORWARD_TO_BASE_EXACT(TraverseType, QualType)317FORWARD_TO_BASE_EXACT(TraverseTypeLoc, TypeLoc)318FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *)319FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc)320FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifierLoc, NestedNameSpecifierLoc)321322template <bool Const>323bool DynamicRecursiveASTVisitorBase<Const>::TraverseLambdaCapture(324MaybeConst<LambdaExpr> *LE, const LambdaCapture *C,325MaybeConst<Expr> *Init) {326return Impl<Const>(*this)327.RecursiveASTVisitor<Impl<Const>>::TraverseLambdaCapture(328const_cast<LambdaExpr *>(LE), C, const_cast<Expr *>(Init));329}330331template <bool Const>332bool DynamicRecursiveASTVisitorBase<Const>::dataTraverseNode(333MaybeConst<Stmt> *S) {334return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::dataTraverseNode(335const_cast<Stmt *>(S), nullptr);336}337338// Declare Traverse*() for and friends all concrete Decl classes.339#define ABSTRACT_DECL(DECL)340#define DECL(CLASS, BASE) \341FORWARD_TO_BASE(Traverse##CLASS##Decl, CLASS##Decl, *) \342FORWARD_TO_BASE(WalkUpFrom##CLASS##Decl, CLASS##Decl, *)343#include "clang/AST/DeclNodes.inc"344345// Declare Traverse*() and friends for all concrete Stmt classes.346#define ABSTRACT_STMT(STMT)347#define STMT(CLASS, PARENT) FORWARD_TO_BASE(Traverse##CLASS, CLASS, *)348#include "clang/AST/StmtNodes.inc"349350#define STMT(CLASS, PARENT) FORWARD_TO_BASE(WalkUpFrom##CLASS, CLASS, *)351#include "clang/AST/StmtNodes.inc"352353// Declare Traverse*() and friends for all concrete Type classes.354#define ABSTRACT_TYPE(CLASS, BASE)355#define TYPE(CLASS, BASE) \356FORWARD_TO_BASE(Traverse##CLASS##Type, CLASS##Type, *) \357FORWARD_TO_BASE(WalkUpFrom##CLASS##Type, CLASS##Type, *)358#include "clang/AST/TypeNodes.inc"359360#define ABSTRACT_TYPELOC(CLASS, BASE)361#define TYPELOC(CLASS, BASE) \362FORWARD_TO_BASE_EXACT(Traverse##CLASS##TypeLoc, CLASS##TypeLoc)363#include "clang/AST/TypeLocNodes.def"364365#define TYPELOC(CLASS, BASE) \366FORWARD_TO_BASE_EXACT(WalkUpFrom##CLASS##TypeLoc, CLASS##TypeLoc)367#include "clang/AST/TypeLocNodes.def"368369namespace clang {370template class DynamicRecursiveASTVisitorBase<false>;371template class DynamicRecursiveASTVisitorBase<true>;372} // namespace clang373374375