-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang] [NFC] Introduce DynamicRecursiveASTVisitor
#105195
Changes from all commits
a43092c
5db2b4c
ac15b6d
5b65237
79ff93d
8133eac
6aa4e98
9a48ed0
8e5616c
9f17945
4bea131
3c16260
e542efa
8e4cab5
73fba50
6f62271
c756a65
883f44b
98350fb
676a069
c603764
19cd494
ad00026
1d2fdba
979eba0
c50f8d1
42f415f
bf8988b
8f7d619
f200083
1340c27
73630ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
#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. | ||
/// | ||
/// This only supports some of the more common visitation operations; in | ||
/// particular, it does not support overriding WalkUpFromX or post-order | ||
/// traversal. | ||
/// | ||
/// Features that are currently not supported: | ||
/// | ||
/// - Visiting attributes | ||
/// - Post-order traversal | ||
/// - Overriding WalkUpFromX | ||
/// - Overriding getStmtChildren() | ||
/// | ||
/// \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; | ||
|
||
public: | ||
virtual void anchor(); | ||
|
||
// Copying/moving a polymorphic type is a bad idea. | ||
DynamicRecursiveASTVisitor(DynamicRecursiveASTVisitor &&) = delete; | ||
DynamicRecursiveASTVisitor(const DynamicRecursiveASTVisitor &) = delete; | ||
DynamicRecursiveASTVisitor &operator=(DynamicRecursiveASTVisitor &&) = delete; | ||
DynamicRecursiveASTVisitor & | ||
operator=(const DynamicRecursiveASTVisitor &) = delete; | ||
Comment on lines
+46
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for being dense, but can you explain why this is a bad idea? We allow copying/moving an RAV, right? (I might be wrong, because I hardly remember I've copied/moved an RAV) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Afaik, you’re generally not supposed to make polymorphic types copyable or movable because of object slicing issues. It would be possible if you want to require everyone who uses it to be careful with it, but I don’t think we ever really need to copy or move an AST visitor, so I figured it would be easier to just disallow it. |
||
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. | ||
bool | ||
TraverseTemplateArguments(ArrayRef<TemplateArgument> Args); // NOT virtual | ||
|
||
/// 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); | ||
|
||
/*// Declare Traverse*() and friends for attributes. | ||
#define DYNAMIC_ATTR_VISITOR_DECLS | ||
#include "clang/AST/AttrVisitor.inc" | ||
#undef DYNAMIC_ATTR_VISITOR_DECLS*/ | ||
|
||
// Not virtual for now because no-one overrides them. | ||
#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 | ||
|
||
// Declare Traverse*() for and friends all concrete Decl classes. | ||
#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" | ||
|
||
// Declare Traverse*() and friends for all concrete Stmt classes. | ||
#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" | ||
|
||
// Declare Traverse*() and friends for all concrete Type classes. | ||
#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" | ||
|
||
#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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget the license header :)