[clang] [Clang] [NFC] Introduce `DynamicRecursiveASTVisitor` (PR #110040)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 25 14:00:54 PDT 2024
https://github.com/Sirraide created https://github.com/llvm/llvm-project/pull/110040
Following the discussion on #105195, we decided to split this into multiple prs. This one is just the DRAV implementation.
Tests for it will be added in a separate pr because testing this involves just rewriting all (or rather, most) of the RAV tests to use DRAV instead—which has the effect of testing both implementations because DRAV uses RAV internally. I’ve already done that and confirmed that it actually works like it’s supposed to (you can build and run the branch mentioned above if you’re interested).
Additional follow-up prs will the subsequently migrate every visitor that can be migrated (most of that work is already done) to use DRAV instead of RAV and also update the documentation to recommend using DRAV if possible.
Some way to tell people about the fact that this is a thing would also help—maybe I should make a Discourse post once this gets merged or something like that? Ideally, we’d want people to start using DRAV instead of RAV whenever possible since that’s kind of the whole reason why we’re adding this...
There is a big comment in DynamicRecursiveASTVisitor.cpp that explains how it works and why it’s implemented this way; this is the best I managed to come up with—if someone has a simpler solution, I’d be more than happy to pivot to that instead, but I couldn’t think of one.
>From a031dd9a1e94c4de4a4346bf7fb719c335c52785 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 25 Sep 2024 22:50:35 +0200
Subject: [PATCH] [Clang] [AST] Introduce DynamicRecursiveASTVisitor
---
.../clang/AST/DynamicRecursiveASTVisitor.h | 268 +++++++++++
clang/lib/AST/CMakeLists.txt | 1 +
clang/lib/AST/DynamicRecursiveASTVisitor.cpp | 452 ++++++++++++++++++
3 files changed, 721 insertions(+)
create mode 100644 clang/include/clang/AST/DynamicRecursiveASTVisitor.h
create mode 100644 clang/lib/AST/DynamicRecursiveASTVisitor.cpp
diff --git a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h
new file mode 100644
index 00000000000000..f0544df93f705f
--- /dev/null
+++ b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h
@@ -0,0 +1,268 @@
+//===--- 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.
+//
+// However, it also comes with limitations in that some of the more seldom
+// utilised features of RecursiveASTVisitor are not supported.
+//
+// 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.
+///
+/// This only supports some of the more common visitation operations; in
+/// particular, it does not support overriding WalkUpFromX or post-order
+/// traversal.
+///
+/// Instead of functions (e.g. shouldVisitImplicitCode()), this class
+/// uses member variables (e.g. ShouldVisitImplicitCode) to control
+/// visitation behaviour.
+///
+/// RAV features that are 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;
+ 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
diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index 6195a16c2c68db..7e5f68b0efd979 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -53,6 +53,7 @@ add_clang_library(clangAST
DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
+ DynamicRecursiveASTVisitor.cpp
ParentMapContext.cpp
Expr.cpp
ExprClassification.cpp
diff --git a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
new file mode 100644
index 00000000000000..8cfabd9f3e93fe
--- /dev/null
+++ b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
@@ -0,0 +1,452 @@
+//=== DynamicRecursiveASTVisitor.cpp - Dynamic AST Visitor Implementation -===//
+//
+// 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 implements DynamicRecursiveASTVisitor in terms of the CRTP-based
+// RecursiveASTVisitor.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/DynamicRecursiveASTVisitor.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+
+using namespace clang;
+
+// The implementation of DRAV deserves some explanation:
+//
+// We want to implement DynamicRecursiveASTVisitor without having to inherit or
+// reference RecursiveASTVisitor in any way in the header: if we instantiate
+// RAV in the header, then every user of (or rather every file that uses) DRAV
+// still has to instantiate a RAV, which gets us nowhere. Moreover, even just
+// including RecursiveASTVisitor.h would probably cause some amount of slowdown
+// because we'd have to parse a huge template. For these reasons, the fact that
+// DRAV is implemented using a RAV is solely an implementation detail.
+//
+// As for the implementation itself, DRAV by default acts exactly like a RAV
+// that overrides none of RAV's functions. There are two parts to this:
+//
+// 1. Any function in DRAV has to act like the corresponding function in RAV,
+// unless overridden by a derived class, of course.
+//
+// 2. Any call to a function by the RAV implementation that DRAV allows to be
+// overridden must be transformed to a virtual call on the user-provided
+// DRAV object: if some function in RAV calls e.g. TraverseCallExpr()
+// during traversal, then the derived class's TraverseCallExpr() must be
+// called (provided it overrides TraverseCallExpr()).
+//
+// The 'Impl' class is a helper that connects the two implementations; it is
+// a wrapper around a reference to a DRAV that is itself a RecursiveASTVisitor.
+// It overrides every function in RAV *that is virtual in DRAV* to perform a
+// virtual call on its DRAV reference. This accomplishes point 2 above.
+//
+// Point 1 is accomplished by, first, having the base class implementation of
+// each of the virtual functions construct an Impl object (which is actually
+// just a no-op), passing in itself so that any virtual calls use the right
+// vtable. Secondly, it then calls RAV's implementation of that same function
+// *on Impl* (using a qualified call so that we actually call into the RAV
+// implementation instead of Impl's version of that same function); this way,
+// we both execute RAV's implementation for this function only and ensure that
+// calls to subsequent functions call into Impl via CRTP (and Impl then calls
+// back into DRAV and so on).
+//
+// While this ends up constructing a lot of Impl instances (almost one per
+// function call), this doesn't really matter since Impl just holds a single
+// pointer, and everything in this file should get inlined into all the DRAV
+// functions here anyway.
+//
+//===----------------------------------------------------------------------===//
+//
+// The following illustrates how a call to an (overridden) function is actually
+// resolved: given some class 'Derived' that derives from DRAV and overrides
+// TraverseStmt(), if we are traversing some AST, and TraverseStmt() is called
+// by the RAV implementation, the following happens:
+//
+// 1. Impl::TraverseStmt() overrides RAV::TraverseStmt() via CRTP, so the
+// former is called.
+//
+// 2. Impl::TraverseStmt() performs a virtual call to the visitor (which is
+// an instance to Derived), so Derived::TraverseStmt() is called.
+//
+// End result: Derived::TraverseStmt() is executed.
+//
+// Suppose some other function, e.g. TraverseCallExpr(), which is NOT overridden
+// by Derived is called, we get:
+//
+// 1. Impl::TraverseCallExpr() overrides RAV::TraverseCallExpr() via CRTP,
+// so the former is called.
+//
+// 2. Impl::TraverseCallExpr() performs a virtual call, but since Derived
+// does not override that function, DRAV::TraverseCallExpr() is called.
+//
+// 3. DRAV::TraverseCallExpr() creates a new instance of Impl, passing in
+// itself (this doesn't change that the pointer is an instance of Derived);
+// it then calls RAV::TraverseCallExpr() on the Impl object, which actually
+// ends up executing RAV's implementation because we used a qualified
+// function call.
+//
+// End result: RAV::TraverseCallExpr() is executed,
+namespace {
+struct Impl : RecursiveASTVisitor<Impl> {
+ DynamicRecursiveASTVisitor &Visitor;
+ Impl(DynamicRecursiveASTVisitor &Visitor) : Visitor(Visitor) {}
+
+ bool shouldVisitTemplateInstantiations() const {
+ return Visitor.ShouldVisitTemplateInstantiations;
+ }
+
+ bool shouldWalkTypesOfTypeLocs() const {
+ return Visitor.ShouldWalkTypesOfTypeLocs;
+ }
+
+ bool shouldVisitImplicitCode() const {
+ return Visitor.ShouldVisitImplicitCode;
+ }
+
+ bool shouldVisitLambdaBody() const { return Visitor.ShouldVisitLambdaBody; }
+
+ // Supporting post-order would be very hard because of quirks of the
+ // RAV implementation that only work with CRTP. It also is only used
+ // by less than 5 visitors in the entire code base.
+ bool shouldTraversePostOrder() const { return false; }
+
+ bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); }
+ bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); }
+ bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); }
+ bool TraverseType(QualType T) { return Visitor.TraverseType(T); }
+ bool TraverseTypeLoc(TypeLoc TL) { return Visitor.TraverseTypeLoc(TL); }
+ bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); }
+
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
+ return Visitor.TraverseConstructorInitializer(Init);
+ }
+
+ bool TraverseTemplateArgument(const TemplateArgument &Arg) {
+ return Visitor.TraverseTemplateArgument(Arg);
+ }
+
+ bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+ return Visitor.TraverseTemplateArgumentLoc(ArgLoc);
+ }
+
+ bool TraverseTemplateName(TemplateName Template) {
+ return Visitor.TraverseTemplateName(Template);
+ }
+
+ bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) {
+ return Visitor.TraverseObjCProtocolLoc(ProtocolLoc);
+ }
+
+ bool TraverseTypeConstraint(const TypeConstraint *C) {
+ return Visitor.TraverseTypeConstraint(C);
+ }
+ bool TraverseConceptRequirement(concepts::Requirement *R) {
+ return Visitor.TraverseConceptRequirement(R);
+ }
+ bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R) {
+ return Visitor.TraverseConceptTypeRequirement(R);
+ }
+ bool TraverseConceptExprRequirement(concepts::ExprRequirement *R) {
+ return Visitor.TraverseConceptExprRequirement(R);
+ }
+ bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R) {
+ return Visitor.TraverseConceptNestedRequirement(R);
+ }
+
+ bool TraverseConceptReference(ConceptReference *CR) {
+ return Visitor.TraverseConceptReference(CR);
+ }
+
+ bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {
+ return Visitor.TraverseCXXBaseSpecifier(Base);
+ }
+
+ bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
+ return Visitor.TraverseDeclarationNameInfo(NameInfo);
+ }
+
+ bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+ return Visitor.TraverseLambdaCapture(LE, C, Init);
+ }
+
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ return Visitor.TraverseNestedNameSpecifier(NNS);
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ return Visitor.TraverseNestedNameSpecifierLoc(NNS);
+ }
+
+ bool VisitConceptReference(ConceptReference *CR) {
+ return Visitor.VisitConceptReference(CR);
+ }
+
+ bool dataTraverseStmtPre(Stmt *S) { return Visitor.dataTraverseStmtPre(S); }
+ bool dataTraverseStmtPost(Stmt *S) { return Visitor.dataTraverseStmtPost(S); }
+
+ // TraverseStmt() always passes in a queue, so we have no choice but to
+ // accept it as a parameter here.
+ bool dataTraverseNode(Stmt *S, DataRecursionQueue * = nullptr) {
+ // But since don't support postorder traversal, we don't need it, so
+ // simply discard it here. This way, derived classes don't need to worry
+ // about including it as a parameter that they never use.
+ return Visitor.dataTraverseNode(S);
+ }
+
+ /// Visit a node.
+ bool VisitAttr(Attr *A) { return Visitor.VisitAttr(A); }
+ bool VisitDecl(Decl *D) { return Visitor.VisitDecl(D); }
+ bool VisitStmt(Stmt *S) { return Visitor.VisitStmt(S); }
+ bool VisitType(Type *T) { return Visitor.VisitType(T); }
+ bool VisitTypeLoc(TypeLoc TL) { return Visitor.VisitTypeLoc(TL); }
+
+#define DEF_TRAVERSE_TMPL_INST(kind) \
+ bool TraverseTemplateInstantiations(kind##TemplateDecl *D) { \
+ return Visitor.TraverseTemplateInstantiations(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) \
+ bool Traverse##CLASS##Decl(CLASS##Decl *D) { \
+ return Visitor.Traverse##CLASS##Decl(D); \
+ }
+#include "clang/AST/DeclNodes.inc"
+
+#define DECL(CLASS, BASE) \
+ bool Visit##CLASS##Decl(CLASS##Decl *D) { \
+ return Visitor.Visit##CLASS##Decl(D); \
+ }
+#include "clang/AST/DeclNodes.inc"
+
+ // Stmts.
+#define ABSTRACT_STMT(STMT)
+#define STMT(CLASS, PARENT) \
+ bool Traverse##CLASS(CLASS *S) { return Visitor.Traverse##CLASS(S); }
+#include "clang/AST/StmtNodes.inc"
+
+#define STMT(CLASS, PARENT) \
+ bool Visit##CLASS(CLASS *S) { return Visitor.Visit##CLASS(S); }
+#include "clang/AST/StmtNodes.inc"
+
+ // Types.
+#define ABSTRACT_TYPE(CLASS, BASE)
+#define TYPE(CLASS, BASE) \
+ bool Traverse##CLASS##Type(CLASS##Type *T) { \
+ return Visitor.Traverse##CLASS##Type(T); \
+ }
+#include "clang/AST/TypeNodes.inc"
+
+#define TYPE(CLASS, BASE) \
+ bool Visit##CLASS##Type(CLASS##Type *T) { \
+ return Visitor.Visit##CLASS##Type(T); \
+ }
+#include "clang/AST/TypeNodes.inc"
+
+ // TypeLocs.
+#define ABSTRACT_TYPELOC(CLASS, BASE)
+#define TYPELOC(CLASS, BASE) \
+ bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
+ return Visitor.Traverse##CLASS##TypeLoc(TL); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+
+#define TYPELOC(CLASS, BASE) \
+ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
+ return Visitor.Visit##CLASS##TypeLoc(TL); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+};
+} // namespace
+
+void DynamicRecursiveASTVisitor::anchor() {}
+
+bool DynamicRecursiveASTVisitor::TraverseAST(ASTContext &AST) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseAST(AST);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseAttr(Attr *At) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseAttr(At);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseConstructorInitializer(
+ CXXCtorInitializer *Init) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseConstructorInitializer(
+ Init);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseDecl(Decl *D) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseDecl(D);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseLambdaCapture(LambdaExpr *LE,
+ const LambdaCapture *C,
+ Expr *Init) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseLambdaCapture(LE, C,
+ Init);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseStmt(Stmt *S) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseStmt(S);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseTemplateArgument(
+ const TemplateArgument &Arg) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseTemplateArgument(Arg);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseTemplateArguments(
+ ArrayRef<TemplateArgument> Args) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseTemplateArguments(Args);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(
+ const TemplateArgumentLoc &ArgLoc) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseTemplateArgumentLoc(
+ ArgLoc);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseTemplateName(TemplateName Template) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseTemplateName(Template);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseType(QualType T) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseType(T);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseTypeLoc(TypeLoc TL) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseTypeLoc(TL);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseTypeConstraint(
+ const TypeConstraint *C) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseTypeConstraint(C);
+}
+bool DynamicRecursiveASTVisitor::TraverseObjCProtocolLoc(
+ ObjCProtocolLoc ProtocolLoc) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseObjCProtocolLoc(
+ ProtocolLoc);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseConceptRequirement(
+ concepts::Requirement *R) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseConceptRequirement(R);
+}
+bool DynamicRecursiveASTVisitor::TraverseConceptTypeRequirement(
+ concepts::TypeRequirement *R) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseConceptTypeRequirement(
+ R);
+}
+bool DynamicRecursiveASTVisitor::TraverseConceptExprRequirement(
+ concepts::ExprRequirement *R) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseConceptExprRequirement(
+ R);
+}
+bool DynamicRecursiveASTVisitor::TraverseConceptNestedRequirement(
+ concepts::NestedRequirement *R) {
+ return Impl(*this)
+ .RecursiveASTVisitor<Impl>::TraverseConceptNestedRequirement(R);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseConceptReference(
+ ConceptReference *CR) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseConceptReference(CR);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseCXXBaseSpecifier(
+ const CXXBaseSpecifier &Base) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseCXXBaseSpecifier(Base);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseDeclarationNameInfo(
+ DeclarationNameInfo NameInfo) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseDeclarationNameInfo(
+ NameInfo);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseNestedNameSpecifier(
+ NestedNameSpecifier *NNS) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseNestedNameSpecifier(
+ NNS);
+}
+
+bool DynamicRecursiveASTVisitor::TraverseNestedNameSpecifierLoc(
+ NestedNameSpecifierLoc NNS) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::TraverseNestedNameSpecifierLoc(
+ NNS);
+}
+
+bool DynamicRecursiveASTVisitor::dataTraverseNode(Stmt *S) {
+ return Impl(*this).RecursiveASTVisitor<Impl>::dataTraverseNode(S, nullptr);
+}
+
+#define DEF_TRAVERSE_TMPL_INST(kind) \
+ bool DynamicRecursiveASTVisitor::TraverseTemplateInstantiations( \
+ kind##TemplateDecl *D) { \
+ return Impl(*this) \
+ .RecursiveASTVisitor<Impl>::TraverseTemplateInstantiations(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) \
+ bool DynamicRecursiveASTVisitor::Traverse##CLASS##Decl(CLASS##Decl *D) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::Traverse##CLASS##Decl(D); \
+ } \
+ bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::WalkUpFrom##CLASS##Decl(D); \
+ }
+#include "clang/AST/DeclNodes.inc"
+
+// Declare Traverse*() and friends for all concrete Stmt classes.
+#define ABSTRACT_STMT(STMT)
+#define STMT(CLASS, PARENT) \
+ bool DynamicRecursiveASTVisitor::Traverse##CLASS(CLASS *S) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::Traverse##CLASS(S); \
+ }
+#include "clang/AST/StmtNodes.inc"
+
+#define STMT(CLASS, PARENT) \
+ bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS(CLASS *S) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::WalkUpFrom##CLASS(S); \
+ }
+#include "clang/AST/StmtNodes.inc"
+
+// Declare Traverse*() and friends for all concrete Typeclasses.
+#define ABSTRACT_TYPE(CLASS, BASE)
+#define TYPE(CLASS, BASE) \
+ bool DynamicRecursiveASTVisitor::Traverse##CLASS##Type(CLASS##Type *T) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::Traverse##CLASS##Type(T); \
+ } \
+ bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS##Type(CLASS##Type *T) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::WalkUpFrom##CLASS##Type(T); \
+ }
+#include "clang/AST/TypeNodes.inc"
+
+#define ABSTRACT_TYPELOC(CLASS, BASE)
+#define TYPELOC(CLASS, BASE) \
+ bool DynamicRecursiveASTVisitor::Traverse##CLASS##TypeLoc( \
+ CLASS##TypeLoc TL) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::Traverse##CLASS##TypeLoc( \
+ TL); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+
+#define TYPELOC(CLASS, BASE) \
+ bool DynamicRecursiveASTVisitor::WalkUpFrom##CLASS##TypeLoc( \
+ CLASS##TypeLoc TL) { \
+ return Impl(*this).RecursiveASTVisitor<Impl>::WalkUpFrom##CLASS##TypeLoc( \
+ TL); \
+ }
+#include "clang/AST/TypeLocNodes.def"
More information about the cfe-commits
mailing list