-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Clang] [NFC] Introduce
DynamicRecursiveASTVisitor
(#110040)
See #105195 as well as the big comment in DynamicRecursiveASTVisitor.cpp for more context.
- Loading branch information
Showing
3 changed files
with
729 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<TemplateArgument> 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.