Skip to content
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

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a43092c
[Clang] Introduce DynamicRecursiveASTVisitor
Sirraide Jun 6, 2024
5db2b4c
[Clang] CollectUnexpandedParameterPacksVisitor
Sirraide Jun 6, 2024
ac15b6d
[Clang] CodeGen
Sirraide Jun 6, 2024
5b65237
[Clang] Separate Traverse() and friends
Sirraide Jun 6, 2024
79ff93d
[Clang] Migrate most of ARCMigrate
Sirraide Jun 6, 2024
8133eac
Disable post-order traversal and overriding WalkUpFromX
Sirraide Jun 10, 2024
6aa4e98
Merge branch 'main' into perf/drav
Sirraide Jul 1, 2024
9a48ed0
Enable overriding Visit for abstract nodes
Sirraide Jul 1, 2024
8e5616c
Migrate more visitors in Sema
Sirraide Jul 1, 2024
9f17945
Migrate more visitors in the AST library
Sirraide Jul 1, 2024
4bea131
Migrate static analyser visitors
Sirraide Jul 1, 2024
3c16260
Actually override Visit for abstract nodes
Sirraide Jul 2, 2024
e542efa
Migrate even more visitors
Sirraide Jul 2, 2024
8e4cab5
Merge branch 'main' into perf/drav
Sirraide Jul 8, 2024
73fba50
Enable overriding dataTraverseStmtPre/Post
Sirraide Jul 15, 2024
6f62271
Migrate more visitors
Sirraide Jul 23, 2024
c756a65
Migrate more visitors, again
Sirraide Jul 23, 2024
883f44b
Merge branch 'main' into perf/drav
Sirraide Aug 16, 2024
98350fb
[Tests] Refactor most tests to use the dynamic visitor
Sirraide Aug 19, 2024
676a069
So long, DataRecursionQueue
Sirraide Aug 19, 2024
c603764
Make a bunch of visitors 'final' to see if that makes a difference
Sirraide Aug 19, 2024
19cd494
Avoid including RecursiveASTVisitor.h wherever possible
Sirraide Aug 19, 2024
ad00026
Make destructor = default
Sirraide Aug 19, 2024
1d2fdba
Revert FallthroughMapper to use CRTP
Sirraide Aug 19, 2024
979eba0
Revert "Revert FallthroughMapper to use CRTP"
Sirraide Aug 19, 2024
c50f8d1
Revert MarkReferencedDecls visitor to use CRTP
Sirraide Aug 19, 2024
42f415f
Revert "Revert MarkReferencedDecls visitor to use CRTP"
Sirraide Aug 20, 2024
bf8988b
Merge branch 'main' into perf/drav
Sirraide Aug 20, 2024
8f7d619
Add missing ObjC includes
Sirraide Aug 20, 2024
f200083
clang-format everything (I hope)
Sirraide Aug 20, 2024
1340c27
clang-format, again
Sirraide Aug 20, 2024
73630ff
clang-format, once more
Sirraide Aug 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions clang/docs/RAVFrontendAction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@ CXXRecordDecl's.

::

class FindNamedClassVisitor
: public RecursiveASTVisitor<FindNamedClassVisitor> {
class FindNamedClassVisitor : public DynamicRecursiveASTVisitor {
public:
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) override {
// For debugging, dumping the AST nodes will show which nodes are already
// being visited.
Declaration->dump();
Expand All @@ -91,7 +90,7 @@ can check for a specific qualified name:

::

bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) override {
if (Declaration->getQualifiedNameAsString() == "n::m::C")
Declaration->dump();
return true;
Expand Down Expand Up @@ -122,7 +121,7 @@ locations:

::

bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) override {
if (Declaration->getQualifiedNameAsString() == "n::m::C") {
// getFullLoc uses the ASTContext's SourceManager to resolve the source
// location and break it up into its line and column parts.
Expand All @@ -143,20 +142,20 @@ Now we can combine all of the above into a small example program:
::

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"

using namespace clang;

class FindNamedClassVisitor
: public RecursiveASTVisitor<FindNamedClassVisitor> {
class FindNamedClassVisitor final : public DynamicRecursiveASTVisitor {
public:
explicit FindNamedClassVisitor(ASTContext *Context)
: Context(Context) {}

bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) override {
if (Declaration->getQualifiedNameAsString() == "n::m::C") {
FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getBeginLoc());
if (FullLocation.isValid())
Expand Down
12 changes: 7 additions & 5 deletions clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Sema.h"
Expand All @@ -41,13 +41,14 @@ bool isMarkedAsCallSuper(const CXXMethodDecl *D) {
return MarkedMethods.contains(D);
}

class MethodUsageVisitor : public RecursiveASTVisitor<MethodUsageVisitor> {
class MethodUsageVisitor final : public DynamicRecursiveASTVisitor {
public:
bool IsOverriddenUsed = false;
explicit MethodUsageVisitor(
llvm::SmallPtrSet<const CXXMethodDecl *, 16> &MustCalledMethods)
: MustCalledMethods(MustCalledMethods) {}
bool VisitCallExpr(CallExpr *CallExpr) {

bool VisitCallExpr(CallExpr *CallExpr) override {
const CXXMethodDecl *Callee = nullptr;
for (const auto &MustCalled : MustCalledMethods) {
if (CallExpr->getCalleeDecl() == MustCalled) {
Expand All @@ -67,7 +68,7 @@ class MethodUsageVisitor : public RecursiveASTVisitor<MethodUsageVisitor> {
llvm::SmallPtrSet<const CXXMethodDecl *, 16> &MustCalledMethods;
};

class CallSuperVisitor : public RecursiveASTVisitor<CallSuperVisitor> {
class CallSuperVisitor final : public DynamicRecursiveASTVisitor {
public:
CallSuperVisitor(DiagnosticsEngine &Diags) : Diags(Diags) {
WarningSuperNotCalled = Diags.getCustomDiagID(
Expand All @@ -77,7 +78,8 @@ class CallSuperVisitor : public RecursiveASTVisitor<CallSuperVisitor> {
NotePreviousCallSuperDeclaration = Diags.getCustomDiagID(
DiagnosticsEngine::Note, "function marked 'call_super' here");
}
bool VisitCXXMethodDecl(CXXMethodDecl *MethodDecl) {

bool VisitCXXMethodDecl(CXXMethodDecl *MethodDecl) override {
if (MethodDecl->isThisDeclarationADefinition() && MethodDecl->hasBody()) {
// First find out which overridden methods are marked as 'call_super'
llvm::SmallPtrSet<const CXXMethodDecl *, 16> OverriddenMarkedMethods;
Expand Down
9 changes: 5 additions & 4 deletions clang/examples/PrintFunctionNames/PrintFunctionNames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Sema/Sema.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
Expand Down Expand Up @@ -52,11 +52,12 @@ class PrintFunctionsConsumer : public ASTConsumer {
// The advantage of doing this in HandleTranslationUnit() is that all
// codegen (when using -add-plugin) is completely finished and this can't
// affect the compiler output.
struct Visitor : public RecursiveASTVisitor<Visitor> {
struct Visitor final : DynamicRecursiveASTVisitor {
const std::set<std::string> &ParsedTemplates;
Visitor(const std::set<std::string> &ParsedTemplates)
: ParsedTemplates(ParsedTemplates) {}
bool VisitFunctionDecl(FunctionDecl *FD) {

bool VisitFunctionDecl(FunctionDecl *FD) override {
if (FD->isLateTemplateParsed() &&
ParsedTemplates.count(FD->getNameAsString()))
LateParsedDecls.insert(FD);
Expand Down
252 changes: 252 additions & 0 deletions clang/include/clang/AST/DynamicRecursiveASTVisitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
#ifndef LLVM_CLANG_AST_DYNAMIC_RECURSIVE_AST_VISITOR_H
Copy link
Contributor

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 :)

#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
Copy link
Contributor

Choose a reason for hiding this comment

The 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)

Copy link
Member Author

Choose a reason for hiding this comment

The 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
Loading