brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.8 KiB · 6d7925b Raw
403 lines · cpp
1//=== DynamicRecursiveASTVisitor.cpp - Dynamic AST Visitor Implementation -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements DynamicRecursiveASTVisitor in terms of the CRTP-based10// RecursiveASTVisitor.11//12//===----------------------------------------------------------------------===//13#include "clang/AST/DynamicRecursiveASTVisitor.h"14#include "clang/AST/RecursiveASTVisitor.h"15 16using namespace clang;17 18// The implementation of DRAV deserves some explanation:19//20// We want to implement DynamicRecursiveASTVisitor without having to inherit or21// reference RecursiveASTVisitor in any way in the header: if we instantiate22// RAV in the header, then every user of (or rather every file that uses) DRAV23// still has to instantiate a RAV, which gets us nowhere. Moreover, even just24// including RecursiveASTVisitor.h would probably cause some amount of slowdown25// because we'd have to parse a huge template. For these reasons, the fact that26// DRAV is implemented using a RAV is solely an implementation detail.27//28// As for the implementation itself, DRAV by default acts exactly like a RAV29// that overrides none of RAV's functions. There are two parts to this:30//31//   1. Any function in DRAV has to act like the corresponding function in RAV,32//      unless overridden by a derived class, of course.33//34//   2. Any call to a function by the RAV implementation that DRAV allows to be35//      overridden must be transformed to a virtual call on the user-provided36//      DRAV object: if some function in RAV calls e.g. TraverseCallExpr()37//      during traversal, then the derived class's TraverseCallExpr() must be38//      called (provided it overrides TraverseCallExpr()).39//40// The 'Impl' class is a helper that connects the two implementations; it is41// a wrapper around a reference to a DRAV that is itself a RecursiveASTVisitor.42// It overrides every function in RAV *that is virtual in DRAV* to perform a43// virtual call on its DRAV reference. This accomplishes point 2 above.44//45// Point 1 is accomplished by, first, having the base class implementation of46// each of the virtual functions construct an Impl object (which is actually47// just a no-op), passing in itself so that any virtual calls use the right48// vtable. Secondly, it then calls RAV's implementation of that same function49// *on Impl* (using a qualified call so that we actually call into the RAV50// implementation instead of Impl's version of that same function); this way,51// we both execute RAV's implementation for this function only and ensure that52// calls to subsequent functions call into Impl via CRTP (and Impl then calls53// back into DRAV and so on).54//55// While this ends up constructing a lot of Impl instances (almost one per56// function call), this doesn't really matter since Impl just holds a single57// pointer, and everything in this file should get inlined into all the DRAV58// functions here anyway.59//60//===----------------------------------------------------------------------===//61//62// The following illustrates how a call to an (overridden) function is actually63// resolved: given some class 'Derived' that derives from DRAV and overrides64// TraverseStmt(), if we are traversing some AST, and TraverseStmt() is called65// by the RAV implementation, the following happens:66//67//   1. Impl::TraverseStmt() overrides RAV::TraverseStmt() via CRTP, so the68//      former is called.69//70//   2. Impl::TraverseStmt() performs a virtual call to the visitor (which is71//      an instance to Derived), so Derived::TraverseStmt() is called.72//73//   End result: Derived::TraverseStmt() is executed.74//75// Suppose some other function, e.g. TraverseCallExpr(), which is NOT overridden76// by Derived is called, we get:77//78//   1. Impl::TraverseCallExpr() overrides RAV::TraverseCallExpr() via CRTP,79//      so the former is called.80//81//   2. Impl::TraverseCallExpr() performs a virtual call, but since Derived82//      does not override that function, DRAV::TraverseCallExpr() is called.83//84//   3. DRAV::TraverseCallExpr() creates a new instance of Impl, passing in85//      itself (this doesn't change that the pointer is an instance of Derived);86//      it then calls RAV::TraverseCallExpr() on the Impl object, which actually87//      ends up executing RAV's implementation because we used a qualified88//      function call.89//90//   End result: RAV::TraverseCallExpr() is executed.91namespace {92template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {93  DynamicRecursiveASTVisitorBase<Const> &Visitor;94  Impl(DynamicRecursiveASTVisitorBase<Const> &Visitor) : Visitor(Visitor) {}95 96  bool shouldVisitTemplateInstantiations() const {97    return Visitor.ShouldVisitTemplateInstantiations;98  }99 100  bool shouldWalkTypesOfTypeLocs() const {101    return Visitor.ShouldWalkTypesOfTypeLocs;102  }103 104  bool shouldVisitImplicitCode() const {105    return Visitor.ShouldVisitImplicitCode;106  }107 108  bool shouldVisitLambdaBody() const { return Visitor.ShouldVisitLambdaBody; }109 110  // Supporting post-order would be very hard because of quirks of the111  // RAV implementation that only work with CRTP. It also is only used112  // by less than 5 visitors in the entire code base.113  bool shouldTraversePostOrder() const { return false; }114 115  bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); }116  bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); }117  bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); }118  bool TraverseType(QualType T, bool TraverseQualifier = true) {119    return Visitor.TraverseType(T, TraverseQualifier);120  }121  bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {122    return Visitor.TraverseTypeLoc(TL, TraverseQualifier);123  }124  bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); }125 126  bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {127    return Visitor.TraverseConstructorInitializer(Init);128  }129 130  bool TraverseTemplateArgument(const TemplateArgument &Arg) {131    return Visitor.TraverseTemplateArgument(Arg);132  }133 134  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {135    return Visitor.TraverseTemplateArgumentLoc(ArgLoc);136  }137 138  bool TraverseTemplateName(TemplateName Template) {139    return Visitor.TraverseTemplateName(Template);140  }141 142  bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) {143    return Visitor.TraverseObjCProtocolLoc(ProtocolLoc);144  }145 146  bool TraverseTypeConstraint(const TypeConstraint *C) {147    return Visitor.TraverseTypeConstraint(C);148  }149  bool TraverseConceptRequirement(concepts::Requirement *R) {150    return Visitor.TraverseConceptRequirement(R);151  }152  bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R) {153    return Visitor.TraverseConceptTypeRequirement(R);154  }155  bool TraverseConceptExprRequirement(concepts::ExprRequirement *R) {156    return Visitor.TraverseConceptExprRequirement(R);157  }158  bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R) {159    return Visitor.TraverseConceptNestedRequirement(R);160  }161 162  bool TraverseConceptReference(ConceptReference *CR) {163    return Visitor.TraverseConceptReference(CR);164  }165 166  bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {167    return Visitor.TraverseCXXBaseSpecifier(Base);168  }169 170  bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {171    return Visitor.TraverseDeclarationNameInfo(NameInfo);172  }173 174  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,175                             Expr *Init) {176    return Visitor.TraverseLambdaCapture(LE, C, Init);177  }178 179  bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {180    return Visitor.TraverseNestedNameSpecifier(NNS);181  }182 183  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {184    return Visitor.TraverseNestedNameSpecifierLoc(NNS);185  }186 187  bool VisitConceptReference(ConceptReference *CR) {188    return Visitor.VisitConceptReference(CR);189  }190 191  bool dataTraverseStmtPre(Stmt *S) { return Visitor.dataTraverseStmtPre(S); }192  bool dataTraverseStmtPost(Stmt *S) { return Visitor.dataTraverseStmtPost(S); }193 194  // TraverseStmt() always passes in a queue, so we have no choice but to195  // accept it as a parameter here.196  bool dataTraverseNode(197      Stmt *S,198      typename RecursiveASTVisitor<Impl>::DataRecursionQueue * = nullptr) {199    // But since we don't support postorder traversal, we don't need it, so200    // simply discard it here. This way, derived classes don't need to worry201    // about including it as a parameter that they never use.202    return Visitor.dataTraverseNode(S);203  }204 205  /// Visit a node.206  bool VisitAttr(Attr *A) { return Visitor.VisitAttr(A); }207  bool VisitDecl(Decl *D) { return Visitor.VisitDecl(D); }208  bool VisitStmt(Stmt *S) { return Visitor.VisitStmt(S); }209  bool VisitType(Type *T) { return Visitor.VisitType(T); }210  bool VisitTypeLoc(TypeLoc TL) { return Visitor.VisitTypeLoc(TL); }211 212#define DEF_TRAVERSE_TMPL_INST(kind)                                           \213  bool TraverseTemplateInstantiations(kind##TemplateDecl *D) {                 \214    return Visitor.TraverseTemplateInstantiations(D);                          \215  }216  DEF_TRAVERSE_TMPL_INST(Class)217  DEF_TRAVERSE_TMPL_INST(Var)218  DEF_TRAVERSE_TMPL_INST(Function)219#undef DEF_TRAVERSE_TMPL_INST220 221  // Decls.222#define ABSTRACT_DECL(DECL)223#define DECL(CLASS, BASE)                                                      \224  bool Traverse##CLASS##Decl(CLASS##Decl *D) {                                 \225    return Visitor.Traverse##CLASS##Decl(D);                                   \226  }227#include "clang/AST/DeclNodes.inc"228 229#define DECL(CLASS, BASE)                                                      \230  bool Visit##CLASS##Decl(CLASS##Decl *D) {                                    \231    return Visitor.Visit##CLASS##Decl(D);                                      \232  }233#include "clang/AST/DeclNodes.inc"234 235  // Stmts.236#define ABSTRACT_STMT(STMT)237#define STMT(CLASS, PARENT)                                                    \238  bool Traverse##CLASS(CLASS *S) { return Visitor.Traverse##CLASS(S); }239#include "clang/AST/StmtNodes.inc"240 241#define STMT(CLASS, PARENT)                                                    \242  bool Visit##CLASS(CLASS *S) { return Visitor.Visit##CLASS(S); }243#include "clang/AST/StmtNodes.inc"244 245  // Types.246#define ABSTRACT_TYPE(CLASS, BASE)247#define TYPE(CLASS, BASE)                                                      \248  bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier) {         \249    return Visitor.Traverse##CLASS##Type(T, TraverseQualifier);                \250  }251#include "clang/AST/TypeNodes.inc"252 253#define TYPE(CLASS, BASE)                                                      \254  bool Visit##CLASS##Type(CLASS##Type *T) {                                    \255    return Visitor.Visit##CLASS##Type(T);                                      \256  }257#include "clang/AST/TypeNodes.inc"258 259  // TypeLocs.260#define ABSTRACT_TYPELOC(CLASS, BASE)261#define TYPELOC(CLASS, BASE)                                                   \262  bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier) {   \263    return Visitor.Traverse##CLASS##TypeLoc(TL, TraverseQualifier);            \264  }265#include "clang/AST/TypeLocNodes.def"266 267#define TYPELOC(CLASS, BASE)                                                   \268  bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) {                              \269    return Visitor.Visit##CLASS##TypeLoc(TL);                                  \270  }271#include "clang/AST/TypeLocNodes.def"272};273} // namespace274 275template <bool Const> void DynamicRecursiveASTVisitorBase<Const>::anchor() {}276 277// Helper macros to forward a call to the base implementation since that278// ends up getting very verbose otherwise.279 280// This calls the RecursiveASTVisitor implementation of the same function,281// stripping any 'const' that the DRAV implementation may have added since282// the RAV implementation largely doesn't use 'const'.283#define FORWARD_TO_BASE(Function, Type, RefOrPointer)                          \284  template <bool Const>                                                        \285  bool DynamicRecursiveASTVisitorBase<Const>::Function(                        \286      MaybeConst<Type> RefOrPointer Param) {                                   \287    return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function(      \288        const_cast<Type RefOrPointer>(Param));                                 \289  }290 291// Same as 'FORWARD_TO_BASE', but doesn't change the parameter type in any way.292#define FORWARD_TO_BASE_EXACT(Function, Type)                                  \293  template <bool Const>                                                        \294  bool DynamicRecursiveASTVisitorBase<Const>::Function(Type Param) {           \295    return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::Function(      \296        Param);                                                                \297  }298 299FORWARD_TO_BASE(TraverseAST, ASTContext, &)300FORWARD_TO_BASE(TraverseAttr, Attr, *)301FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *)302FORWARD_TO_BASE(TraverseDecl, Decl, *)303FORWARD_TO_BASE(TraverseStmt, Stmt, *)304FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *)305FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *)306FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *)307FORWARD_TO_BASE(TraverseConceptRequirement, concepts::Requirement, *)308FORWARD_TO_BASE(TraverseConceptTypeRequirement, concepts::TypeRequirement, *)309FORWARD_TO_BASE(TraverseConceptExprRequirement, concepts::ExprRequirement, *)310FORWARD_TO_BASE(TraverseConceptReference, ConceptReference, *)311FORWARD_TO_BASE(TraverseConceptNestedRequirement,312                concepts::NestedRequirement, *)313 314FORWARD_TO_BASE_EXACT(TraverseCXXBaseSpecifier, const CXXBaseSpecifier &)315FORWARD_TO_BASE_EXACT(TraverseDeclarationNameInfo, DeclarationNameInfo)316FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &)317FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef<TemplateArgument>)318FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &)319FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName)320FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifier, NestedNameSpecifier)321 322template <bool Const>323bool DynamicRecursiveASTVisitorBase<Const>::TraverseType(324    QualType T, bool TraverseQualifier) {325  return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseType(326      T, TraverseQualifier);327}328 329template <bool Const>330bool DynamicRecursiveASTVisitorBase<Const>::TraverseTypeLoc(331    TypeLoc TL, bool TraverseQualifier) {332  return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseTypeLoc(333      TL, TraverseQualifier);334}335 336FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *)337FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc)338FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifierLoc, NestedNameSpecifierLoc)339 340template <bool Const>341bool DynamicRecursiveASTVisitorBase<Const>::TraverseLambdaCapture(342    MaybeConst<LambdaExpr> *LE, const LambdaCapture *C,343    MaybeConst<Expr> *Init) {344  return Impl<Const>(*this)345      .RecursiveASTVisitor<Impl<Const>>::TraverseLambdaCapture(346          const_cast<LambdaExpr *>(LE), C, const_cast<Expr *>(Init));347}348 349template <bool Const>350bool DynamicRecursiveASTVisitorBase<Const>::dataTraverseNode(351    MaybeConst<Stmt> *S) {352  return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::dataTraverseNode(353      const_cast<Stmt *>(S), nullptr);354}355 356// Declare Traverse*() for and friends all concrete Decl classes.357#define ABSTRACT_DECL(DECL)358#define DECL(CLASS, BASE)                                                      \359  FORWARD_TO_BASE(Traverse##CLASS##Decl, CLASS##Decl, *)                       \360  FORWARD_TO_BASE(WalkUpFrom##CLASS##Decl, CLASS##Decl, *)361#include "clang/AST/DeclNodes.inc"362 363// Declare Traverse*() and friends for all concrete Stmt classes.364#define ABSTRACT_STMT(STMT)365#define STMT(CLASS, PARENT) FORWARD_TO_BASE(Traverse##CLASS, CLASS, *)366#include "clang/AST/StmtNodes.inc"367 368#define STMT(CLASS, PARENT) FORWARD_TO_BASE(WalkUpFrom##CLASS, CLASS, *)369#include "clang/AST/StmtNodes.inc"370 371// Declare Traverse*() and friends for all concrete Type classes.372#define ABSTRACT_TYPE(CLASS, BASE)373#define TYPE(CLASS, BASE)                                                      \374  template <bool Const>                                                        \375  bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##Type(           \376      MaybeConst<CLASS##Type> *T, bool TraverseQualifier) {                    \377    return Impl<Const>(*this)                                                  \378        .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##Type(              \379            const_cast<CLASS##Type *>(T), TraverseQualifier);                  \380  }                                                                            \381  FORWARD_TO_BASE(WalkUpFrom##CLASS##Type, CLASS##Type, *)382#include "clang/AST/TypeNodes.inc"383 384#define ABSTRACT_TYPELOC(CLASS, BASE)385#define TYPELOC(CLASS, BASE)                                                   \386  template <bool Const>                                                        \387  bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##TypeLoc(        \388      CLASS##TypeLoc TL, bool TraverseQualifier) {                             \389    return Impl<Const>(*this)                                                  \390        .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##TypeLoc(           \391            TL, TraverseQualifier);                                            \392  }393#include "clang/AST/TypeLocNodes.def"394 395#define TYPELOC(CLASS, BASE)                                                   \396  FORWARD_TO_BASE_EXACT(WalkUpFrom##CLASS##TypeLoc, CLASS##TypeLoc)397#include "clang/AST/TypeLocNodes.def"398 399namespace clang {400template class DynamicRecursiveASTVisitorBase<false>;401template class DynamicRecursiveASTVisitorBase<true>;402} // namespace clang403