[Clang] [Tests] Refactor most unit tests to use DynamicRecursiveASTVisitor (#115132)

This pr refactors most tests that use RAV to use DRAV instead; this also
has the nice effect of testing both the RAV and DRAV implementations at
the same time w/o having to duplicate all of our AST visitor tests.

Some tests rely on features that DRAV doesn’t support (mainly post-order
traversal), so those haven’t been migrated. At the same time,
`TestVisitor` is now a DRAV, so I’ve had to introduce a new
`CTRPTestVisitor` for any tests that need to use RAV directly.
This commit is contained in:
Sirraide
2024-11-15 06:17:20 +01:00
committed by GitHub
parent c2a9bba4a3
commit 4e600751d2
44 changed files with 380 additions and 361 deletions

View File

@@ -13,7 +13,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
#include <map>
@@ -28,8 +28,8 @@ typedef std::map<std::string, bool> VarInfoMap;
/// \brief Records information on variable initializers to a map.
class EvaluateConstantInitializersVisitor
: public clang::RecursiveASTVisitor<EvaluateConstantInitializersVisitor> {
public:
: public clang::DynamicRecursiveASTVisitor {
public:
explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)
: VarInfo(VarInfo) {}
@@ -38,7 +38,7 @@ class EvaluateConstantInitializersVisitor
///
/// For each VarDecl with an initializer this also records in VarInfo
/// whether the initializer could be evaluated as a constant.
bool VisitVarDecl(const clang::VarDecl *VD) {
bool VisitVarDecl(clang::VarDecl *VD) override {
if (const clang::Expr *Init = VD->getInit()) {
clang::Expr::EvalResult Result;
bool WasEvaluated = Init->EvaluateAsRValue(Result, VD->getASTContext());
@@ -109,9 +109,9 @@ TEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) {
}
class CheckLValueToRValueConversionVisitor
: public clang::RecursiveASTVisitor<CheckLValueToRValueConversionVisitor> {
: public clang::DynamicRecursiveASTVisitor {
public:
bool VisitDeclRefExpr(const clang::DeclRefExpr *E) {
bool VisitDeclRefExpr(clang::DeclRefExpr *E) override {
clang::Expr::EvalResult Result;
E->EvaluateAsRValue(Result, E->getDecl()->getASTContext(), true);

View File

@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/CloneDetection.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
@@ -15,15 +15,14 @@ namespace clang {
namespace analysis {
namespace {
class CloneDetectionVisitor
: public RecursiveASTVisitor<CloneDetectionVisitor> {
class CloneDetectionVisitor : public DynamicRecursiveASTVisitor {
CloneDetector &Detector;
public:
explicit CloneDetectionVisitor(CloneDetector &D) : Detector(D) {}
bool VisitFunctionDecl(FunctionDecl *D) {
bool VisitFunctionDecl(FunctionDecl *D) override {
Detector.analyzeCodeBody(D);
return true;
}

View File

@@ -9,7 +9,7 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -53,7 +53,7 @@ public:
}
private:
class Visitor : public ASTConsumer, public RecursiveASTVisitor<Visitor> {
class Visitor : public ASTConsumer, public DynamicRecursiveASTVisitor {
public:
Visitor(CompilerInstance &CI, bool ActOnEndOfTranslationUnit,
std::vector<std::string> &decl_names) :
@@ -67,7 +67,7 @@ private:
TraverseDecl(context.getTranslationUnitDecl());
}
virtual bool VisitNamedDecl(NamedDecl *Decl) {
bool VisitNamedDecl(NamedDecl *Decl) override {
decl_names_.push_back(Decl->getQualifiedNameAsString());
return true;
}

View File

@@ -26,7 +26,7 @@ struct FileLocation {
using FileRange = std::pair<FileLocation, FileLocation>;
class SelectionFinderVisitor : public TestVisitor<SelectionFinderVisitor> {
class SelectionFinderVisitor : public TestVisitor {
FileLocation Location;
std::optional<FileRange> SelectionRange;
llvm::function_ref<void(SourceRange SelectionRange,
@@ -42,7 +42,7 @@ public:
: Location(Location), SelectionRange(SelectionRange), Consumer(Consumer) {
}
bool VisitTranslationUnitDecl(const TranslationUnitDecl *TU) {
bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) override {
const ASTContext &Context = TU->getASTContext();
const SourceManager &SM = Context.getSourceManager();

View File

@@ -0,0 +1,42 @@
//===--- TestVisitor.h ------------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines a CRTP-based RecursiveASTVisitor helper for tests.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_UNITTESTS_TOOLING_CRTPTESTVISITOR_H
#define LLVM_CLANG_UNITTESTS_TOOLING_CRTPTESTVISITOR_H
#include "TestVisitor.h"
#include "clang/AST/RecursiveASTVisitor.h"
// CRTP versions of the visitors in TestVisitor.h.
namespace clang {
template <typename T>
class CRTPTestVisitor : public RecursiveASTVisitor<T>,
public detail::TestVisitorHelper {
public:
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
void InvokeTraverseDecl(TranslationUnitDecl *D) override {
RecursiveASTVisitor<T>::TraverseDecl(D);
}
};
template <typename T>
class CRTPExpectedLocationVisitor
: public CRTPTestVisitor<T>,
public detail::ExpectedLocationVisitorHelper {
ASTContext *getASTContext() override { return this->Context; }
};
} // namespace clang
#endif // LLVM_CLANG_UNITTESTS_TOOLING_CRTPTESTVISITOR_H

View File

@@ -12,17 +12,17 @@ using namespace clang;
namespace {
struct CastExprVisitor : TestVisitor<CastExprVisitor> {
struct CastExprVisitor : TestVisitor {
std::function<void(ExplicitCastExpr *)> OnExplicitCast;
std::function<void(CastExpr *)> OnCast;
bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) {
bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) override {
if (OnExplicitCast)
OnExplicitCast(Expr);
return true;
}
bool VisitCastExpr(CastExpr *Expr) {
bool VisitCastExpr(CastExpr *Expr) override {
if (OnCast)
OnCast(Expr);
return true;

View File

@@ -22,12 +22,9 @@ struct Comment {
class CommentVerifier;
typedef std::vector<Comment> CommentList;
class CommentHandlerVisitor : public TestVisitor<CommentHandlerVisitor>,
public CommentHandler {
typedef TestVisitor<CommentHandlerVisitor> base;
class CommentHandlerVisitor : public TestVisitor, public CommentHandler {
public:
CommentHandlerVisitor() : base(), PP(nullptr), Verified(false) {}
CommentHandlerVisitor() : PP(nullptr), Verified(false) {}
~CommentHandlerVisitor() override {
EXPECT_TRUE(Verified) << "CommentVerifier not accessed";
@@ -64,7 +61,7 @@ private:
CommentList Comments;
bool Verified;
class CommentHandlerAction : public base::TestAction {
class CommentHandlerAction : public TestAction {
public:
CommentHandlerAction(CommentHandlerVisitor *Visitor)
: TestAction(Visitor) { }

View File

@@ -9,7 +9,7 @@
#include "clang/Tooling/Execution.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
@@ -30,12 +30,9 @@ namespace {
// This traverses the AST and outputs function name as key and "1" as value for
// each function declaration.
class ASTConsumerWithResult
: public ASTConsumer,
public RecursiveASTVisitor<ASTConsumerWithResult> {
class ASTConsumerWithResult : public ASTConsumer,
public DynamicRecursiveASTVisitor {
public:
using ASTVisitor = RecursiveASTVisitor<ASTConsumerWithResult>;
explicit ASTConsumerWithResult(ExecutionContext *Context) : Context(Context) {
assert(Context != nullptr);
}
@@ -44,12 +41,12 @@ public:
TraverseDecl(Context.getTranslationUnitDecl());
}
bool TraverseFunctionDecl(clang::FunctionDecl *Decl) {
bool TraverseFunctionDecl(clang::FunctionDecl *Decl) override {
Context->reportResult(Decl->getNameAsString(),
Context->getRevision() + ":" + Context->getCorpus() +
":" + Context->getCurrentCompilationUnit() +
"/1");
return ASTVisitor::TraverseFunctionDecl(Decl);
return DynamicRecursiveASTVisitor::TraverseFunctionDecl(Decl);
}
private:

View File

@@ -44,13 +44,14 @@ private:
llvm::SmallVector<Decl *, 8> TraversalStack;
};
class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
class DummyMatchVisitor : public ExpectedLocationVisitor {
bool EmitDeclIndices, EmitStmtIndices;
public:
DummyMatchVisitor(bool EmitDeclIndices = false, bool EmitStmtIndices = false)
: EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) override {
const ASTContext &Context = TU->getASTContext();
const SourceManager &SM = Context.getSourceManager();
LexicallyOrderedDeclVisitor SubVisitor(*this, SM, EmitDeclIndices,

View File

@@ -13,31 +13,31 @@
using namespace clang;
namespace {
struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> {
struct GetDeclsVisitor : TestVisitor {
std::function<void(CallExpr *)> OnCall;
std::function<void(RecordTypeLoc)> OnRecordTypeLoc;
std::function<void(UsingTypeLoc)> OnUsingTypeLoc;
SmallVector<Decl *, 4> DeclStack;
bool VisitCallExpr(CallExpr *Expr) {
bool VisitCallExpr(CallExpr *Expr) override {
if (OnCall)
OnCall(Expr);
return true;
}
bool VisitRecordTypeLoc(RecordTypeLoc Loc) {
bool VisitRecordTypeLoc(RecordTypeLoc Loc) override {
if (OnRecordTypeLoc)
OnRecordTypeLoc(Loc);
return true;
}
bool VisitUsingTypeLoc(UsingTypeLoc Loc) {
bool VisitUsingTypeLoc(UsingTypeLoc Loc) override {
if (OnUsingTypeLoc)
OnUsingTypeLoc(Loc);
return true;
}
bool TraverseDecl(Decl *D) {
bool TraverseDecl(Decl *D) override {
DeclStack.push_back(D);
bool Ret = TestVisitor::TraverseDecl(D);
DeclStack.pop_back();

View File

@@ -11,12 +11,12 @@
using namespace clang;
namespace {
struct TypeNameVisitor : TestVisitor<TypeNameVisitor> {
struct TypeNameVisitor : TestVisitor {
llvm::StringMap<std::string> ExpectedQualTypeNames;
bool WithGlobalNsPrefix = false;
// ValueDecls are the least-derived decl with both a qualtype and a name.
bool VisitValueDecl(const ValueDecl *VD) {
bool VisitValueDecl(ValueDecl *VD) override {
std::string ExpectedName =
ExpectedQualTypeNames.lookup(VD->getNameAsString());
if (ExpectedName != "") {

View File

@@ -12,12 +12,12 @@ using namespace clang;
namespace {
class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
class VarDeclVisitor : public ExpectedLocationVisitor {
public:
bool VisitVarDecl(VarDecl *Variable) {
Match(Variable->getNameAsString(), Variable->getBeginLoc());
return true;
}
bool VisitVarDecl(VarDecl *Variable) override {
Match(Variable->getNameAsString(), Variable->getBeginLoc());
return true;
}
};
TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
@@ -29,12 +29,11 @@ TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
VarDeclVisitor::Lang_CXX11));
}
class ParmVarDeclVisitorForImplicitCode :
public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> {
class ParmVarDeclVisitorForImplicitCode : public ExpectedLocationVisitor {
public:
bool shouldVisitImplicitCode() const { return true; }
ParmVarDeclVisitorForImplicitCode() { ShouldVisitImplicitCode = true; }
bool VisitParmVarDecl(ParmVarDecl *ParamVar) {
bool VisitParmVarDecl(ParmVarDecl *ParamVar) override {
Match(ParamVar->getNameAsString(), ParamVar->getBeginLoc());
return true;
}
@@ -58,10 +57,9 @@ TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) {
"void bar(Y a) {Y b = a;}"));
}
class NamedDeclVisitor
: public ExpectedLocationVisitor<NamedDeclVisitor> {
class NamedDeclVisitor : public ExpectedLocationVisitor {
public:
bool VisitNamedDecl(NamedDecl *Decl) {
bool VisitNamedDecl(NamedDecl *Decl) override {
std::string NameWithTemplateArgs;
llvm::raw_string_ostream OS(NameWithTemplateArgs);
Decl->getNameForDiagnostic(OS,

View File

@@ -11,14 +11,12 @@
//
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
#include "CRTPTestVisitor.h"
using namespace clang;
namespace {
class RecordingVisitor : public TestVisitor<RecordingVisitor> {
class RecordingVisitor : public CRTPTestVisitor<RecordingVisitor> {
bool VisitPostOrder;
public:

View File

@@ -12,9 +12,9 @@ using namespace clang;
namespace {
class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
class TypeLocVisitor : public ExpectedLocationVisitor {
public:
bool VisitTypeLoc(TypeLoc TypeLocation) {
bool VisitTypeLoc(TypeLoc TypeLocation) override {
Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc());
return true;
}

View File

@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
#include "CRTPTestVisitor.h"
using namespace clang;
@@ -14,7 +14,7 @@ namespace {
// Check to ensure that attributes and expressions within them are being
// visited.
class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
class AttrVisitor : public CRTPExpectedLocationVisitor<AttrVisitor> {
public:
bool VisitMemberExpr(MemberExpr *ME) {
Match(ME->getMemberDecl()->getNameAsString(), ME->getBeginLoc());
@@ -30,7 +30,6 @@ public:
}
};
TEST(RecursiveASTVisitor, AttributesAreVisited) {
AttrVisitor Visitor;
Visitor.ExpectMatch("Attr", 4, 24);

View File

@@ -14,10 +14,9 @@ using namespace clang;
namespace {
// Check to ensure that bitfield initializers are visited.
class BitfieldInitializerVisitor
: public ExpectedLocationVisitor<BitfieldInitializerVisitor> {
class BitfieldInitializerVisitor : public ExpectedLocationVisitor {
public:
bool VisitIntegerLiteral(IntegerLiteral *IL) {
bool VisitIntegerLiteral(IntegerLiteral *IL) override {
Match(std::to_string(IL->getValue().getSExtValue()), IL->getLocation());
return true;
}

View File

@@ -12,10 +12,9 @@ using namespace clang;
namespace {
class CXXBoolLiteralExprVisitor
: public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
class CXXBoolLiteralExprVisitor : public ExpectedLocationVisitor {
public:
bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) override {
if (BE->getValue())
Match("true", BE->getLocation());
else

View File

@@ -12,10 +12,9 @@ using namespace clang;
namespace {
class CXXMemberCallVisitor
: public ExpectedLocationVisitor<CXXMemberCallVisitor> {
class CXXMemberCallVisitor : public ExpectedLocationVisitor {
public:
bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) {
bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) override {
Match(Call->getMethodDecl()->getQualifiedNameAsString(),
Call->getBeginLoc());
return true;

View File

@@ -13,25 +13,21 @@ using namespace clang;
namespace {
class CXXMethodDeclVisitor
: public ExpectedLocationVisitor<CXXMethodDeclVisitor> {
class CXXMethodDeclVisitor : public ExpectedLocationVisitor {
public:
CXXMethodDeclVisitor(bool VisitImplicitCode)
: VisitImplicitCode(VisitImplicitCode) {}
CXXMethodDeclVisitor(bool VisitImplicitCode) {
ShouldVisitImplicitCode = VisitImplicitCode;
}
bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
bool VisitDeclRefExpr(DeclRefExpr *D) {
bool VisitDeclRefExpr(DeclRefExpr *D) override {
Match("declref", D->getLocation());
return true;
}
bool VisitParmVarDecl(ParmVarDecl *P) {
bool VisitParmVarDecl(ParmVarDecl *P) override {
Match("parm", P->getLocation());
return true;
}
private:
bool VisitImplicitCode;
};
TEST(RecursiveASTVisitor, CXXMethodDeclNoDefaultBodyVisited) {

View File

@@ -12,15 +12,13 @@ using namespace clang;
namespace {
class CXXOperatorCallExprTraverser
: public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> {
class CXXOperatorCallExprTraverser : public ExpectedLocationVisitor {
public:
// Use Traverse, not Visit, to check that data recursion optimization isn't
// bypassing the call of this function.
bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) override {
Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc());
return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>::
TraverseCXXOperatorCallExpr(CE);
return ExpectedLocationVisitor::TraverseCXXOperatorCallExpr(CE);
}
};

View File

@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
#include "CRTPTestVisitor.h"
using namespace clang;
@@ -21,7 +21,7 @@ enum class ShouldTraversePostOrder : bool {
/// sequence of calls to user-defined callbacks like Traverse*(), WalkUp*(),
/// Visit*().
template <typename Derived>
class RecordingVisitorBase : public TestVisitor<Derived> {
class RecordingVisitorBase : public CRTPTestVisitor<Derived> {
ShouldTraversePostOrder ShouldTraversePostOrderValue;
public:

View File

@@ -14,10 +14,11 @@ namespace {
// Checks for lambda classes that are not marked as implicitly-generated.
// (There should be none.)
class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> {
class ClassVisitor : public ExpectedLocationVisitor {
public:
ClassVisitor() : SawNonImplicitLambdaClass(false) {}
bool VisitCXXRecordDecl(CXXRecordDecl* record) {
bool VisitCXXRecordDecl(CXXRecordDecl *record) override {
if (record->isLambda() && !record->isImplicit())
SawNonImplicitLambdaClass = true;
return true;

View File

@@ -16,78 +16,87 @@ using namespace clang;
namespace {
struct ConceptVisitor : ExpectedLocationVisitor<ConceptVisitor> {
bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
struct ConceptVisitor : ExpectedLocationVisitor {
ConceptVisitor(bool VisitImplicitCode = false) {
ShouldVisitImplicitCode = VisitImplicitCode;
}
bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) override {
++ConceptSpecializationExprsVisited;
return true;
}
bool TraverseTypeConstraint(const TypeConstraint *C) {
bool TraverseTypeConstraint(const TypeConstraint *C) override {
++TypeConstraintsTraversed;
return ExpectedLocationVisitor::TraverseTypeConstraint(C);
}
bool TraverseConceptRequirement(concepts::Requirement *R) {
bool TraverseConceptRequirement(concepts::Requirement *R) override {
++ConceptRequirementsTraversed;
return ExpectedLocationVisitor::TraverseConceptRequirement(R);
}
bool TraverseConceptReference(ConceptReference *CR) {
bool TraverseConceptReference(ConceptReference *CR) override {
++ConceptReferencesTraversed;
return ExpectedLocationVisitor::TraverseConceptReference(CR);
}
bool VisitConceptReference(ConceptReference *CR) {
bool VisitConceptReference(ConceptReference *CR) override {
++ConceptReferencesVisited;
return true;
}
bool shouldVisitImplicitCode() { return ShouldVisitImplicitCode; }
int ConceptSpecializationExprsVisited = 0;
int TypeConstraintsTraversed = 0;
int ConceptRequirementsTraversed = 0;
int ConceptReferencesTraversed = 0;
int ConceptReferencesVisited = 0;
bool ShouldVisitImplicitCode = false;
};
TEST(RecursiveASTVisitor, Concepts) {
{
ConceptVisitor Visitor{true};
EXPECT_TRUE(
Visitor.runOver("template <typename T> concept Fooable = true;\n"
"template <Fooable T> void bar(T);",
ConceptVisitor::Lang_CXX2a));
// Check that we traverse the "Fooable T" template parameter's
// TypeConstraint's ImmediatelyDeclaredConstraint, which is a
// ConceptSpecializationExpr.
EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited);
// Also check we traversed the TypeConstraint that produced the expr.
EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesVisited);
}
{
ConceptVisitor Visitor; // Don't visit implicit code now.
EXPECT_TRUE(
Visitor.runOver("template <typename T> concept Fooable = true;\n"
"template <Fooable T> void bar(T);",
ConceptVisitor::Lang_CXX2a));
// Check that we only visit the TypeConstraint, but not the implicitly
// generated immediately declared expression.
EXPECT_EQ(0, Visitor.ConceptSpecializationExprsVisited);
EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesVisited);
}
{
ConceptVisitor Visitor;
EXPECT_TRUE(
Visitor.runOver("template <class T> concept A = true;\n"
"template <class T> struct vector {};\n"
"template <class T> concept B = requires(T x) {\n"
" typename vector<T*>;\n"
" {x} -> A;\n"
" requires true;\n"
"};",
ConceptVisitor::Lang_CXX2a));
EXPECT_EQ(3, Visitor.ConceptRequirementsTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesVisited);
}
ConceptVisitor Visitor;
Visitor.ShouldVisitImplicitCode = true;
EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n"
"template <Fooable T> void bar(T);",
ConceptVisitor::Lang_CXX2a));
// Check that we traverse the "Fooable T" template parameter's
// TypeConstraint's ImmediatelyDeclaredConstraint, which is a
// ConceptSpecializationExpr.
EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited);
// Also check we traversed the TypeConstraint that produced the expr.
EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesVisited);
Visitor = {}; // Don't visit implicit code now.
EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n"
"template <Fooable T> void bar(T);",
ConceptVisitor::Lang_CXX2a));
// Check that we only visit the TypeConstraint, but not the implicitly
// generated immediately declared expression.
EXPECT_EQ(0, Visitor.ConceptSpecializationExprsVisited);
EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesVisited);
Visitor = {};
EXPECT_TRUE(Visitor.runOver("template <class T> concept A = true;\n"
"template <class T> struct vector {};\n"
"template <class T> concept B = requires(T x) {\n"
" typename vector<T*>;\n"
" {x} -> A;\n"
" requires true;\n"
"};",
ConceptVisitor::Lang_CXX2a));
EXPECT_EQ(3, Visitor.ConceptRequirementsTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
EXPECT_EQ(1, Visitor.ConceptReferencesVisited);
Visitor = {};
llvm::StringRef Code =
R"cpp(
template<typename T> concept True = false;
@@ -107,34 +116,34 @@ struct Foo<F> {};
EXPECT_EQ(2, Visitor.ConceptReferencesVisited);
}
struct VisitDeclOnlyOnce : ExpectedLocationVisitor<VisitDeclOnlyOnce> {
bool VisitConceptDecl(ConceptDecl *D) {
struct VisitDeclOnlyOnce : ExpectedLocationVisitor {
VisitDeclOnlyOnce() { ShouldWalkTypesOfTypeLocs = false; }
bool VisitConceptDecl(ConceptDecl *D) override {
++ConceptDeclsVisited;
return true;
}
bool VisitAutoType(AutoType *) {
bool VisitAutoType(AutoType *) override {
++AutoTypeVisited;
return true;
}
bool VisitAutoTypeLoc(AutoTypeLoc) {
bool VisitAutoTypeLoc(AutoTypeLoc) override {
++AutoTypeLocVisited;
return true;
}
bool VisitConceptReference(ConceptReference *) {
bool VisitConceptReference(ConceptReference *) override {
++ConceptReferencesVisited;
return true;
}
bool TraverseVarDecl(VarDecl *V) {
bool TraverseVarDecl(VarDecl *V) override {
// The base traversal visits only the `TypeLoc`.
// However, in the test we also validate the underlying `QualType`.
TraverseType(V->getType());
return ExpectedLocationVisitor::TraverseVarDecl(V);
}
bool shouldWalkTypesOfTypeLocs() { return false; }
int ConceptDeclsVisited = 0;
int AutoTypeVisited = 0;
int AutoTypeLocVisited = 0;

View File

@@ -18,18 +18,11 @@ namespace {
/// The name recorded for the match is the name of the class whose constructor
/// is invoked by the CXXConstructExpr, not the name of the class whose
/// constructor the CXXConstructExpr is contained in.
class ConstructExprVisitor
: public ExpectedLocationVisitor<ConstructExprVisitor> {
class ConstructExprVisitor : public ExpectedLocationVisitor {
public:
ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
ConstructExprVisitor() { ShouldVisitImplicitCode = false; }
bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
void setShouldVisitImplicitCode(bool NewValue) {
ShouldVisitImplicitCode = NewValue;
}
bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
bool VisitCXXConstructExpr(CXXConstructExpr *Expr) override {
if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
if (const CXXRecordDecl* Class = Ctor->getParent()) {
Match(Class->getName(), Expr->getLocation());
@@ -37,14 +30,11 @@ public:
}
return true;
}
private:
bool ShouldVisitImplicitCode;
};
TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
ConstructExprVisitor Visitor;
Visitor.setShouldVisitImplicitCode(true);
Visitor.ShouldVisitImplicitCode = true;
Visitor.ExpectMatch("WithCtor", 2, 8);
// Simple has a constructor that implicitly initializes 'w'. Test
// that a visitor that visits implicit code visits that initialization.
@@ -60,7 +50,7 @@ TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
// visits are omitted when the visitor does not include implicit code.
TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
ConstructExprVisitor Visitor;
Visitor.setShouldVisitImplicitCode(false);
Visitor.ShouldVisitImplicitCode = false;
Visitor.DisallowMatch("WithCtor", 2, 8);
// Simple has a constructor that implicitly initializes 'w'. Test
// that a visitor that skips implicit code skips that initialization.

View File

@@ -12,23 +12,14 @@ using namespace clang;
namespace {
class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
class DeclRefExprVisitor : public ExpectedLocationVisitor {
public:
DeclRefExprVisitor() : ShouldVisitImplicitCode(false) {}
DeclRefExprVisitor() { ShouldVisitImplicitCode = false; }
bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
void setShouldVisitImplicitCode(bool NewValue) {
ShouldVisitImplicitCode = NewValue;
}
bool VisitDeclRefExpr(DeclRefExpr *Reference) {
bool VisitDeclRefExpr(DeclRefExpr *Reference) override {
Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
return true;
}
private:
bool ShouldVisitImplicitCode;
};
TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
@@ -73,7 +64,7 @@ TEST(RecursiveASTVisitor, VisitsUseOfImplicitLambdaCapture) {
TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) {
DeclRefExprVisitor Visitor;
Visitor.setShouldVisitImplicitCode(true);
Visitor.ShouldVisitImplicitCode = true;
// We're expecting "i" to be visited twice: once for the initialization expr
// for the captured variable "i" outside of the lambda body, and again for
// the use of "i" inside the lambda.

View File

@@ -13,23 +13,20 @@ using namespace clang;
namespace {
class DeductionGuideVisitor
: public ExpectedLocationVisitor<DeductionGuideVisitor> {
class DeductionGuideVisitor : public ExpectedLocationVisitor {
public:
DeductionGuideVisitor(bool ShouldVisitImplicitCode)
: ShouldVisitImplicitCode(ShouldVisitImplicitCode) {}
bool VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
DeductionGuideVisitor(bool VisitImplicitCode) {
ShouldVisitImplicitCode = VisitImplicitCode;
ShouldVisitTemplateInstantiations = false;
}
bool VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) override {
std::string Storage;
llvm::raw_string_ostream Stream(Storage);
D->print(Stream);
Match(Storage, D->getLocation());
return true;
}
bool shouldVisitTemplateInstantiations() const { return false; }
bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
bool ShouldVisitImplicitCode;
};
TEST(RecursiveASTVisitor, DeductionGuideNonImplicitMode) {

View File

@@ -13,12 +13,9 @@ using namespace clang;
namespace {
// A visitor that visits implicit declarations and matches constructors.
class ImplicitCtorVisitor
: public ExpectedLocationVisitor<ImplicitCtorVisitor> {
class ImplicitCtorVisitor : public ExpectedLocationVisitor {
public:
bool shouldVisitImplicitCode() const { return true; }
bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
bool VisitCXXConstructorDecl(CXXConstructorDecl *Ctor) override {
if (Ctor->isImplicit()) { // Was not written in source code
if (const CXXRecordDecl* Class = Ctor->getParent()) {
Match(Class->getName(), Ctor->getLocation());

View File

@@ -12,26 +12,20 @@ using namespace clang;
namespace {
class CXXCtorInitializerVisitor
: public ExpectedLocationVisitor<CXXCtorInitializerVisitor> {
class CXXCtorInitializerVisitor : public ExpectedLocationVisitor {
public:
CXXCtorInitializerVisitor(bool VisitImplicitCode)
: VisitImplicitCode(VisitImplicitCode) {}
CXXCtorInitializerVisitor(bool VisitImplicitCode) {
ShouldVisitImplicitCode = VisitImplicitCode;
}
bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
bool TraverseConstructorInitializer(CXXCtorInitializer *Init) override {
if (!Init->isWritten())
VisitedImplicitInitializer = true;
Match("initializer", Init->getSourceLocation());
return ExpectedLocationVisitor<
CXXCtorInitializerVisitor>::TraverseConstructorInitializer(Init);
return ExpectedLocationVisitor::TraverseConstructorInitializer(Init);
}
bool VisitedImplicitInitializer = false;
private:
bool VisitImplicitCode;
};
// Check to ensure that CXXCtorInitializer is not visited when implicit code

View File

@@ -6,14 +6,14 @@
//
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
#include "CRTPTestVisitor.h"
using namespace clang;
namespace {
class InitListExprPostOrderVisitor
: public ExpectedLocationVisitor<InitListExprPostOrderVisitor> {
: public CRTPExpectedLocationVisitor<InitListExprPostOrderVisitor> {
public:
bool shouldTraversePostOrder() const { return true; }

View File

@@ -6,19 +6,19 @@
//
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
#include "CRTPTestVisitor.h"
using namespace clang;
namespace {
class InitListExprPostOrderNoQueueVisitor
: public ExpectedLocationVisitor<InitListExprPostOrderNoQueueVisitor> {
: public CRTPExpectedLocationVisitor<InitListExprPostOrderNoQueueVisitor> {
public:
bool shouldTraversePostOrder() const { return true; }
bool TraverseInitListExpr(InitListExpr *ILE) {
return ExpectedLocationVisitor::TraverseInitListExpr(ILE);
return CRTPExpectedLocationVisitor::TraverseInitListExpr(ILE);
}
bool VisitInitListExpr(InitListExpr *ILE) {

View File

@@ -14,21 +14,16 @@ namespace {
// Check to ensure that InitListExpr is visited twice, once each for the
// syntactic and semantic form.
class InitListExprPreOrderVisitor
: public ExpectedLocationVisitor<InitListExprPreOrderVisitor> {
class InitListExprPreOrderVisitor : public ExpectedLocationVisitor {
public:
InitListExprPreOrderVisitor(bool VisitImplicitCode)
: VisitImplicitCode(VisitImplicitCode) {}
InitListExprPreOrderVisitor(bool VisitImplicitCode) {
ShouldVisitImplicitCode = VisitImplicitCode;
}
bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
bool VisitInitListExpr(InitListExpr *ILE) {
bool VisitInitListExpr(InitListExpr *ILE) override {
Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getBeginLoc());
return true;
}
private:
bool VisitImplicitCode;
};
TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) {

View File

@@ -12,14 +12,13 @@ using namespace clang;
namespace {
class InitListExprPreOrderNoQueueVisitor
: public ExpectedLocationVisitor<InitListExprPreOrderNoQueueVisitor> {
class InitListExprPreOrderNoQueueVisitor : public ExpectedLocationVisitor {
public:
bool TraverseInitListExpr(InitListExpr *ILE) {
bool TraverseInitListExpr(InitListExpr *ILE) override {
return ExpectedLocationVisitor::TraverseInitListExpr(ILE);
}
bool VisitInitListExpr(InitListExpr *ILE) {
bool VisitInitListExpr(InitListExpr *ILE) override {
Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getBeginLoc());
return true;
}

View File

@@ -13,10 +13,9 @@ using namespace clang;
namespace {
// Check to ensure that implicit default argument expressions are visited.
class IntegerLiteralVisitor
: public ExpectedLocationVisitor<IntegerLiteralVisitor> {
class IntegerLiteralVisitor : public ExpectedLocationVisitor {
public:
bool VisitIntegerLiteral(const IntegerLiteral *IL) {
bool VisitIntegerLiteral(IntegerLiteral *IL) override {
Match("literal", IL->getLocation());
return true;
}

View File

@@ -13,10 +13,9 @@ using namespace clang;
namespace {
// Matches the (optional) capture-default of a lambda-introducer.
class LambdaDefaultCaptureVisitor
: public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
class LambdaDefaultCaptureVisitor : public ExpectedLocationVisitor {
public:
bool VisitLambdaExpr(LambdaExpr *Lambda) {
bool VisitLambdaExpr(LambdaExpr *Lambda) override {
if (Lambda->getCaptureDefault() != LCD_None) {
Match("", Lambda->getCaptureDefaultLoc());
}

View File

@@ -14,9 +14,11 @@ using namespace clang;
namespace {
class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
class LambdaExprVisitor : public ExpectedLocationVisitor {
public:
bool VisitLambdaExpr(LambdaExpr *Lambda) {
LambdaExprVisitor() { ShouldVisitImplicitCode = false; }
bool VisitLambdaExpr(LambdaExpr *Lambda) override {
PendingBodies.push(Lambda->getBody());
PendingClasses.push(Lambda->getLambdaClass());
Match("", Lambda->getIntroducerRange().getBegin());
@@ -24,12 +26,12 @@ public:
}
/// For each call to VisitLambdaExpr, we expect a subsequent call to visit
/// the body (and maybe the lambda class, which is implicit).
bool VisitStmt(Stmt *S) {
bool VisitStmt(Stmt *S) override {
if (!PendingBodies.empty() && S == PendingBodies.top())
PendingBodies.pop();
return true;
}
bool VisitDecl(Decl *D) {
bool VisitDecl(Decl *D) override {
if (!PendingClasses.empty() && D == PendingClasses.top())
PendingClasses.pop();
return true;
@@ -38,9 +40,6 @@ public:
bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); }
bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); }
bool VisitImplicitCode = false;
bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
private:
std::stack<Stmt *> PendingBodies;
std::stack<Decl *> PendingClasses;
@@ -67,7 +66,7 @@ TEST(RecursiveASTVisitor, LambdaInLambda) {
TEST(RecursiveASTVisitor, TopLevelLambda) {
LambdaExprVisitor Visitor;
Visitor.VisitImplicitCode = true;
Visitor.ShouldVisitImplicitCode = true;
Visitor.ExpectMatch("", 1, 10);
Visitor.ExpectMatch("", 1, 14);
EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };",
@@ -78,7 +77,7 @@ TEST(RecursiveASTVisitor, TopLevelLambda) {
TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) {
LambdaExprVisitor Visitor;
Visitor.VisitImplicitCode = true;
Visitor.ShouldVisitImplicitCode = true;
Visitor.ExpectMatch("", 1, 12);
EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
LambdaExprVisitor::Lang_CXX11));

View File

@@ -13,24 +13,23 @@ using namespace clang;
namespace {
// Matches (optional) explicit template parameters.
class LambdaTemplateParametersVisitor
: public ExpectedLocationVisitor<LambdaTemplateParametersVisitor> {
class LambdaTemplateParametersVisitor : public ExpectedLocationVisitor {
public:
bool shouldVisitImplicitCode() const { return false; }
LambdaTemplateParametersVisitor() { ShouldVisitImplicitCode = false; }
bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) override {
EXPECT_FALSE(D->isImplicit());
Match(D->getName(), D->getBeginLoc());
return true;
}
bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) override {
EXPECT_FALSE(D->isImplicit());
Match(D->getName(), D->getBeginLoc());
return true;
}
bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) override {
EXPECT_FALSE(D->isImplicit());
Match(D->getName(), D->getBeginLoc());
return true;

View File

@@ -13,16 +13,15 @@ using namespace clang;
namespace {
class MemberPointerTypeLocVisitor
: public ExpectedLocationVisitor<MemberPointerTypeLocVisitor> {
class MemberPointerTypeLocVisitor : public ExpectedLocationVisitor {
public:
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) override {
if (!TL)
return true;
Match(TL.getDecl()->getName(), TL.getNameLoc());
return true;
}
bool VisitRecordTypeLoc(RecordTypeLoc RTL) {
bool VisitRecordTypeLoc(RecordTypeLoc RTL) override {
if (!RTL)
return true;
Match(RTL.getDecl()->getName(), RTL.getNameLoc());

View File

@@ -13,17 +13,16 @@ using namespace clang;
namespace {
// Check to ensure that nested name specifiers are visited.
class NestedNameSpecifiersVisitor
: public ExpectedLocationVisitor<NestedNameSpecifiersVisitor> {
class NestedNameSpecifiersVisitor : public ExpectedLocationVisitor {
public:
bool VisitRecordTypeLoc(RecordTypeLoc RTL) {
bool VisitRecordTypeLoc(RecordTypeLoc RTL) override {
if (!RTL)
return true;
Match(RTL.getDecl()->getName(), RTL.getNameLoc());
return true;
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) override {
if (!NNS)
return true;
if (const NamespaceDecl *ND =

View File

@@ -12,9 +12,9 @@ using namespace clang;
namespace {
class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
class ParenExprVisitor : public ExpectedLocationVisitor {
public:
bool VisitParenExpr(ParenExpr *Parens) {
bool VisitParenExpr(ParenExpr *Parens) override {
Match("", Parens->getExprLoc());
return true;
}

View File

@@ -12,18 +12,16 @@ using namespace clang;
namespace {
class TemplateArgumentLocTraverser
: public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
class TemplateArgumentLocTraverser : public ExpectedLocationVisitor {
public:
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) override {
std::string ArgStr;
llvm::raw_string_ostream Stream(ArgStr);
const TemplateArgument &Arg = ArgLoc.getArgument();
Arg.print(Context->getPrintingPolicy(), Stream, /*IncludeType*/ true);
Match(ArgStr, ArgLoc.getLocation());
return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
TraverseTemplateArgumentLoc(ArgLoc);
return ExpectedLocationVisitor::TraverseTemplateArgumentLoc(ArgLoc);
}
};

View File

@@ -12,17 +12,17 @@ using namespace clang;
namespace {
class Visitor : public ExpectedLocationVisitor<Visitor, clang::TestVisitor> {
class Visitor : public ExpectedLocationVisitor {
public:
Visitor(ASTContext *Context) { this->Context = Context; }
bool VisitTranslationUnitDecl(TranslationUnitDecl *D) {
bool VisitTranslationUnitDecl(TranslationUnitDecl *D) override {
auto &SM = D->getParentASTContext().getSourceManager();
Match("TU", SM.getLocForStartOfFile(SM.getMainFileID()));
return true;
}
bool VisitNamedDecl(NamedDecl *D) {
bool VisitNamedDecl(NamedDecl *D) override {
if (!D->isImplicit())
Match(D->getName(), D->getLocation());
return true;

View File

@@ -13,7 +13,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
@@ -647,8 +647,7 @@ TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
}
namespace {
template <typename T>
class TestVisitor : public clang::RecursiveASTVisitor<T> {
class TestVisitor : public DynamicRecursiveASTVisitor {
public:
bool runOver(StringRef Code) {
return runToolOnCode(std::make_unique<TestAction>(this), Code);
@@ -698,9 +697,9 @@ void expectReplacementAt(const Replacement &Replace,
EXPECT_EQ(Length, Replace.getLength());
}
class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
class ClassDeclXVisitor : public TestVisitor {
public:
bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
bool VisitCXXRecordDecl(CXXRecordDecl *Record) override {
if (Record->getName() == "X") {
Replace = Replacement(*SM, Record, "");
}
@@ -721,9 +720,9 @@ TEST(Replacement, ReplacesAtSpellingLocation) {
expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
}
class CallToFVisitor : public TestVisitor<CallToFVisitor> {
class CallToFVisitor : public TestVisitor {
public:
bool VisitCallExpr(CallExpr *Call) {
bool VisitCallExpr(CallExpr *Call) override {
if (Call->getDirectCallee()->getName() == "F") {
Replace = Replacement(*SM, Call, "");
}
@@ -745,10 +744,9 @@ TEST(Replacement, TemplatedFunctionCall) {
expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
}
class NestedNameSpecifierAVisitor
: public TestVisitor<NestedNameSpecifierAVisitor> {
class NestedNameSpecifierAVisitor : public TestVisitor {
public:
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) override {
if (NNSLoc.getNestedNameSpecifier()) {
if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) {
if (NS->getName() == "a") {
@@ -756,8 +754,7 @@ public:
}
}
}
return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc(
NNSLoc);
return TestVisitor::TraverseNestedNameSpecifierLoc(NNSLoc);
}
Replacement Replace;
};

View File

@@ -35,8 +35,8 @@ using tooling::validateEditRange;
namespace {
struct IntLitVisitor : TestVisitor<IntLitVisitor> {
bool VisitIntegerLiteral(IntegerLiteral *Expr) {
struct IntLitVisitor : TestVisitor {
bool VisitIntegerLiteral(IntegerLiteral *Expr) override {
OnIntLit(Expr, Context);
return true;
}
@@ -44,8 +44,8 @@ struct IntLitVisitor : TestVisitor<IntLitVisitor> {
std::function<void(IntegerLiteral *, ASTContext *Context)> OnIntLit;
};
struct CallsVisitor : TestVisitor<CallsVisitor> {
bool VisitCallExpr(CallExpr *Expr) {
struct CallsVisitor : TestVisitor {
bool VisitCallExpr(CallExpr *Expr) override {
OnCall(Expr, Context);
return true;
}
@@ -53,8 +53,8 @@ struct CallsVisitor : TestVisitor<CallsVisitor> {
std::function<void(CallExpr *, ASTContext *Context)> OnCall;
};
struct TypeLocVisitor : TestVisitor<TypeLocVisitor> {
bool VisitTypeLoc(TypeLoc TL) {
struct TypeLocVisitor : TestVisitor {
bool VisitTypeLoc(TypeLoc TL) override {
OnTypeLoc(TL, Context);
return true;
}
@@ -97,7 +97,7 @@ static ::testing::Matcher<CharSourceRange> AsRange(const SourceManager &SM,
// Base class for visitors that expect a single match corresponding to a
// specific annotated range.
template <typename T> class AnnotatedCodeVisitor : public TestVisitor<T> {
class AnnotatedCodeVisitor : public TestVisitor {
protected:
int MatchCount = 0;
llvm::Annotations Code;
@@ -199,9 +199,8 @@ TEST(SourceCodeTest, getExtendedText) {
}
TEST(SourceCodeTest, maybeExtendRange_TokenRange) {
struct ExtendTokenRangeVisitor
: AnnotatedCodeVisitor<ExtendTokenRangeVisitor> {
bool VisitCallExpr(CallExpr *CE) {
struct ExtendTokenRangeVisitor : AnnotatedCodeVisitor {
bool VisitCallExpr(CallExpr *CE) override {
++MatchCount;
EXPECT_THAT(getExtendedRange(*CE, tok::TokenKind::semi, *Context),
EqualsAnnotatedRange(Context, Code.range("r")));
@@ -218,8 +217,8 @@ TEST(SourceCodeTest, maybeExtendRange_TokenRange) {
}
TEST(SourceCodeTest, maybeExtendRange_CharRange) {
struct ExtendCharRangeVisitor : AnnotatedCodeVisitor<ExtendCharRangeVisitor> {
bool VisitCallExpr(CallExpr *CE) {
struct ExtendCharRangeVisitor : AnnotatedCodeVisitor {
bool VisitCallExpr(CallExpr *CE) override {
++MatchCount;
CharSourceRange Call = Lexer::getAsCharRange(CE->getSourceRange(),
Context->getSourceManager(),
@@ -238,8 +237,8 @@ TEST(SourceCodeTest, maybeExtendRange_CharRange) {
}
TEST(SourceCodeTest, getAssociatedRange) {
struct VarDeclsVisitor : AnnotatedCodeVisitor<VarDeclsVisitor> {
bool VisitVarDecl(VarDecl *Decl) { return VisitDeclHelper(Decl); }
struct VarDeclsVisitor : AnnotatedCodeVisitor {
bool VisitVarDecl(VarDecl *Decl) override { return VisitDeclHelper(Decl); }
};
VarDeclsVisitor Visitor;
@@ -283,8 +282,10 @@ TEST(SourceCodeTest, getAssociatedRange) {
}
TEST(SourceCodeTest, getAssociatedRangeClasses) {
struct RecordDeclsVisitor : AnnotatedCodeVisitor<RecordDeclsVisitor> {
bool VisitRecordDecl(RecordDecl *Decl) { return VisitDeclHelper(Decl); }
struct RecordDeclsVisitor : AnnotatedCodeVisitor {
bool VisitRecordDecl(RecordDecl *Decl) override {
return VisitDeclHelper(Decl);
}
};
RecordDeclsVisitor Visitor;
@@ -297,8 +298,8 @@ TEST(SourceCodeTest, getAssociatedRangeClasses) {
}
TEST(SourceCodeTest, getAssociatedRangeClassTemplateSpecializations) {
struct CXXRecordDeclsVisitor : AnnotatedCodeVisitor<CXXRecordDeclsVisitor> {
bool VisitCXXRecordDecl(CXXRecordDecl *Decl) {
struct CXXRecordDeclsVisitor : AnnotatedCodeVisitor {
bool VisitCXXRecordDecl(CXXRecordDecl *Decl) override {
return Decl->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization ||
VisitDeclHelper(Decl);
@@ -315,8 +316,10 @@ TEST(SourceCodeTest, getAssociatedRangeClassTemplateSpecializations) {
}
TEST(SourceCodeTest, getAssociatedRangeFunctions) {
struct FunctionDeclsVisitor : AnnotatedCodeVisitor<FunctionDeclsVisitor> {
bool VisitFunctionDecl(FunctionDecl *Decl) { return VisitDeclHelper(Decl); }
struct FunctionDeclsVisitor : AnnotatedCodeVisitor {
bool VisitFunctionDecl(FunctionDecl *Decl) override {
return VisitDeclHelper(Decl);
}
};
FunctionDeclsVisitor Visitor;
@@ -328,8 +331,8 @@ TEST(SourceCodeTest, getAssociatedRangeFunctions) {
}
TEST(SourceCodeTest, getAssociatedRangeMemberTemplates) {
struct CXXMethodDeclsVisitor : AnnotatedCodeVisitor<CXXMethodDeclsVisitor> {
bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
struct CXXMethodDeclsVisitor : AnnotatedCodeVisitor {
bool VisitCXXMethodDecl(CXXMethodDecl *Decl) override {
// Only consider the definition of the template.
return !Decl->doesThisDeclarationHaveABody() || VisitDeclHelper(Decl);
}
@@ -346,8 +349,8 @@ TEST(SourceCodeTest, getAssociatedRangeMemberTemplates) {
}
TEST(SourceCodeTest, getAssociatedRangeWithComments) {
struct VarDeclsVisitor : AnnotatedCodeVisitor<VarDeclsVisitor> {
bool VisitVarDecl(VarDecl *Decl) { return VisitDeclHelper(Decl); }
struct VarDeclsVisitor : AnnotatedCodeVisitor {
bool VisitVarDecl(VarDecl *Decl) override { return VisitDeclHelper(Decl); }
};
VarDeclsVisitor Visitor;
@@ -447,9 +450,9 @@ TEST(SourceCodeTest, getAssociatedRangeWithComments) {
}
TEST(SourceCodeTest, getAssociatedRangeInvalidForPartialExpansions) {
struct FailingVarDeclsVisitor : TestVisitor<FailingVarDeclsVisitor> {
struct FailingVarDeclsVisitor : TestVisitor {
FailingVarDeclsVisitor() {}
bool VisitVarDecl(VarDecl *Decl) {
bool VisitVarDecl(VarDecl *Decl) override {
EXPECT_TRUE(getAssociatedRange(*Decl, *Context).isInvalid());
return true;
}

View File

@@ -16,7 +16,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
@@ -24,20 +24,11 @@
#include <vector>
namespace clang {
/// \brief Base class for simple RecursiveASTVisitor based tests.
///
/// This is a drop-in replacement for RecursiveASTVisitor itself, with the
/// additional capability of running it over a snippet of code.
///
/// Visits template instantiations and implicit code by default.
template <typename T>
class TestVisitor : public RecursiveASTVisitor<T> {
namespace detail {
// Use 'TestVisitor' or include 'CRTPTestVisitor.h' and use 'CRTPTestVisitor'
// instead of using this directly.
class TestVisitorHelper {
public:
TestVisitor() { }
virtual ~TestVisitor() { }
enum Language {
Lang_C,
Lang_CXX98,
@@ -54,57 +45,63 @@ public:
bool runOver(StringRef Code, Language L = Lang_CXX) {
std::vector<std::string> Args;
switch (L) {
case Lang_C:
Args.push_back("-x");
Args.push_back("c");
break;
case Lang_CXX98: Args.push_back("-std=c++98"); break;
case Lang_CXX11: Args.push_back("-std=c++11"); break;
case Lang_CXX14: Args.push_back("-std=c++14"); break;
case Lang_CXX17: Args.push_back("-std=c++17"); break;
case Lang_CXX2a: Args.push_back("-std=c++2a"); break;
case Lang_OBJC:
Args.push_back("-ObjC");
Args.push_back("-fobjc-runtime=macosx-10.12.0");
break;
case Lang_OBJCXX11:
Args.push_back("-ObjC++");
Args.push_back("-std=c++11");
Args.push_back("-fblocks");
break;
case Lang_C:
Args.push_back("-x");
Args.push_back("c");
break;
case Lang_CXX98:
Args.push_back("-std=c++98");
break;
case Lang_CXX11:
Args.push_back("-std=c++11");
break;
case Lang_CXX14:
Args.push_back("-std=c++14");
break;
case Lang_CXX17:
Args.push_back("-std=c++17");
break;
case Lang_CXX2a:
Args.push_back("-std=c++2a");
break;
case Lang_OBJC:
Args.push_back("-ObjC");
Args.push_back("-fobjc-runtime=macosx-10.12.0");
break;
case Lang_OBJCXX11:
Args.push_back("-ObjC++");
Args.push_back("-std=c++11");
Args.push_back("-fblocks");
break;
}
return tooling::runToolOnCodeWithArgs(CreateTestAction(), Code, Args);
}
bool shouldVisitTemplateInstantiations() const {
return true;
}
bool shouldVisitImplicitCode() const {
return true;
}
protected:
TestVisitorHelper() = default;
virtual ~TestVisitorHelper() = default;
virtual void InvokeTraverseDecl(TranslationUnitDecl *D) = 0;
virtual std::unique_ptr<ASTFrontendAction> CreateTestAction() {
return std::make_unique<TestAction>(this);
}
class FindConsumer : public ASTConsumer {
public:
FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
FindConsumer(TestVisitorHelper *Visitor) : Visitor(Visitor) {}
void HandleTranslationUnit(clang::ASTContext &Context) override {
Visitor->Context = &Context;
Visitor->TraverseDecl(Context.getTranslationUnitDecl());
Visitor->InvokeTraverseDecl(Context.getTranslationUnitDecl());
}
private:
TestVisitor *Visitor;
TestVisitorHelper *Visitor;
};
class TestAction : public ASTFrontendAction {
public:
TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
TestAction(TestVisitorHelper *Visitor) : Visitor(Visitor) {}
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) override {
@@ -113,20 +110,13 @@ protected:
}
protected:
TestVisitor *Visitor;
TestVisitorHelper *Visitor;
};
ASTContext *Context;
};
/// \brief A RecursiveASTVisitor to check that certain matches are (or are
/// not) observed during visitation.
///
/// This is a RecursiveASTVisitor for testing the RecursiveASTVisitor itself,
/// and allows simple creation of test visitors running matches on only a small
/// subset of the Visit* methods.
template <typename T, template <typename> class Visitor = TestVisitor>
class ExpectedLocationVisitor : public Visitor<T> {
class ExpectedLocationVisitorHelper {
public:
/// \brief Expect 'Match' *not* to occur at the given 'Line' and 'Column'.
///
@@ -147,37 +137,44 @@ public:
}
/// \brief Checks that all expected matches have been found.
~ExpectedLocationVisitor() override {
for (typename std::vector<ExpectedMatch>::const_iterator
It = ExpectedMatches.begin(), End = ExpectedMatches.end();
virtual ~ExpectedLocationVisitorHelper() {
// FIXME: Range-based for loop.
for (std::vector<ExpectedMatch>::const_iterator
It = ExpectedMatches.begin(),
End = ExpectedMatches.end();
It != End; ++It) {
It->ExpectFound();
}
}
protected:
virtual ASTContext *getASTContext() = 0;
/// \brief Checks an actual match against expected and disallowed matches.
///
/// Implementations are required to call this with appropriate values
/// for 'Name' during visitation.
void Match(StringRef Name, SourceLocation Location) {
const FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
const FullSourceLoc FullLocation = getASTContext()->getFullLoc(Location);
for (typename std::vector<MatchCandidate>::const_iterator
It = DisallowedMatches.begin(), End = DisallowedMatches.end();
// FIXME: Range-based for loop.
for (std::vector<MatchCandidate>::const_iterator
It = DisallowedMatches.begin(),
End = DisallowedMatches.end();
It != End; ++It) {
EXPECT_FALSE(It->Matches(Name, FullLocation))
<< "Matched disallowed " << *It;
}
for (typename std::vector<ExpectedMatch>::iterator
It = ExpectedMatches.begin(), End = ExpectedMatches.end();
// FIXME: Range-based for loop.
for (std::vector<ExpectedMatch>::iterator It = ExpectedMatches.begin(),
End = ExpectedMatches.end();
It != End; ++It) {
It->UpdateFor(Name, FullLocation, this->Context->getSourceManager());
It->UpdateFor(Name, FullLocation, getASTContext()->getSourceManager());
}
}
private:
private:
struct MatchCandidate {
std::string ExpectedName;
unsigned LineNumber;
@@ -247,6 +244,41 @@ protected:
std::vector<MatchCandidate> DisallowedMatches;
std::vector<ExpectedMatch> ExpectedMatches;
};
}
} // namespace detail
/// \brief Base class for simple (Dynamic)RecursiveASTVisitor based tests.
///
/// This is a drop-in replacement for DynamicRecursiveASTVisitor itself, with
/// the additional capability of running it over a snippet of code.
///
/// Visits template instantiations and implicit code by default.
///
/// For post-order traversal etc. use CTRPTestVisitor from
/// CTRPTestVisitor.h instead.
class TestVisitor : public DynamicRecursiveASTVisitor,
public detail::TestVisitorHelper {
public:
TestVisitor() {
ShouldVisitTemplateInstantiations = true;
ShouldVisitImplicitCode = true;
}
void InvokeTraverseDecl(TranslationUnitDecl *D) override { TraverseDecl(D); }
};
/// \brief A RecursiveASTVisitor to check that certain matches are (or are
/// not) observed during visitation.
///
/// This is a RecursiveASTVisitor for testing the RecursiveASTVisitor itself,
/// and allows simple creation of test visitors running matches on only a small
/// subset of the Visit* methods.
///
/// For post-order traversal etc. use CTRPExpectedLocationVisitor from
/// CTRPTestVisitor.h instead.
class ExpectedLocationVisitor : public TestVisitor,
public detail::ExpectedLocationVisitorHelper {
ASTContext *getASTContext() override { return Context; }
};
} // namespace clang
#endif