//===- unittest/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp ------------===// // // 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 // //===----------------------------------------------------------------------===// #include "TestVisitor.h" using namespace clang; namespace { class VarDeclVisitor : public ExpectedLocationVisitor { public: bool VisitVarDecl(VarDecl *Variable) { Match(Variable->getNameAsString(), Variable->getBeginLoc()); return true; } }; TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) { VarDeclVisitor Visitor; Visitor.ExpectMatch("i", 2, 17); EXPECT_TRUE(Visitor.runOver( "int x[5];\n" "void f() { for (int i : x) {} }", VarDeclVisitor::Lang_CXX11)); } class ParmVarDeclVisitorForImplicitCode : public ExpectedLocationVisitor { public: bool shouldVisitImplicitCode() const { return true; } bool VisitParmVarDecl(ParmVarDecl *ParamVar) { Match(ParamVar->getNameAsString(), ParamVar->getBeginLoc()); return true; } }; // Test RAV visits parameter variable declaration of the implicit // copy assignment operator and implicit copy constructor. TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) { ParmVarDeclVisitorForImplicitCode Visitor; // Match parameter variable name of implicit copy assignment operator and // implicit copy constructor. // This parameter name does not have a valid IdentifierInfo, and shares // same SourceLocation with its class declaration, so we match an empty name // with the class' source location. Visitor.ExpectMatch("", 1, 7); Visitor.ExpectMatch("", 3, 7); EXPECT_TRUE(Visitor.runOver( "class X {};\n" "void foo(X a, X b) {a = b;}\n" "class Y {};\n" "void bar(Y a) {Y b = a;}")); } class NamedDeclVisitor : public ExpectedLocationVisitor { public: bool VisitNamedDecl(NamedDecl *Decl) { std::string NameWithTemplateArgs; llvm::raw_string_ostream OS(NameWithTemplateArgs); Decl->getNameForDiagnostic(OS, Decl->getASTContext().getPrintingPolicy(), true); Match(OS.str(), Decl->getLocation()); return true; } }; TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) { // From cfe-commits/Week-of-Mon-20100830/033998.html // Contrary to the approach suggested in that email, we visit all // specializations when we visit the primary template. Visiting them when we // visit the associated specialization is problematic for specializations of // template members of class templates. NamedDeclVisitor Visitor; Visitor.ExpectMatch("A", 1, 26); Visitor.ExpectMatch("A", 2, 26); EXPECT_TRUE(Visitor.runOver( "template class A {};\n" "template class A {};\n" "A ab;\n" "A acp;\n")); } TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) { NamedDeclVisitor Visitor; Visitor.ExpectMatch("A", 1, 29); EXPECT_TRUE(Visitor.runOver( "template struct A;\n" "A *p;\n")); } TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) { NamedDeclVisitor Visitor; Visitor.ExpectMatch("A::B", 2, 31); EXPECT_TRUE(Visitor.runOver( "template struct A {\n" " template struct B;\n" "};\n" "A::B *p;\n")); } TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) { NamedDeclVisitor Visitor; Visitor.ExpectMatch("A", 1, 26); EXPECT_TRUE(Visitor.runOver( "template int A();\n" "int k = A();\n")); } TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) { NamedDeclVisitor Visitor; Visitor.ExpectMatch("A::B", 2, 35); EXPECT_TRUE(Visitor.runOver( "template struct A {\n" " template static int B();\n" "};\n" "int k = A::B();\n")); } TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) { // From cfe-commits/Week-of-Mon-20100830/033977.html NamedDeclVisitor Visitor; Visitor.ExpectMatch("vector_iterator", 2, 7); EXPECT_TRUE(Visitor.runOver( "template\n" "class vector_iterator {\n" " template friend class vector_iterator;\n" "};\n" "vector_iterator it_int;\n")); } } // end anonymous namespace