|  | //===- 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<VarDeclVisitor> { | 
|  | 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<ParmVarDeclVisitorForImplicitCode> { | 
|  | 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<NamedDeclVisitor> { | 
|  | 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<bool>", 1, 26); | 
|  | Visitor.ExpectMatch("A<char *>", 2, 26); | 
|  | EXPECT_TRUE(Visitor.runOver( | 
|  | "template <class T> class A {};\n" | 
|  | "template <class T> class A<T*> {};\n" | 
|  | "A<bool> ab;\n" | 
|  | "A<char*> acp;\n")); | 
|  | } | 
|  |  | 
|  | TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) { | 
|  | NamedDeclVisitor Visitor; | 
|  | Visitor.ExpectMatch("A<int>", 1, 29); | 
|  | EXPECT_TRUE(Visitor.runOver( | 
|  | "template<typename T> struct A;\n" | 
|  | "A<int> *p;\n")); | 
|  | } | 
|  |  | 
|  | TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) { | 
|  | NamedDeclVisitor Visitor; | 
|  | Visitor.ExpectMatch("A<int>::B<char>", 2, 31); | 
|  | EXPECT_TRUE(Visitor.runOver( | 
|  | "template<typename T> struct A {\n" | 
|  | "  template<typename U> struct B;\n" | 
|  | "};\n" | 
|  | "A<int>::B<char> *p;\n")); | 
|  | } | 
|  |  | 
|  | TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) { | 
|  | NamedDeclVisitor Visitor; | 
|  | Visitor.ExpectMatch("A<int>", 1, 26); | 
|  | EXPECT_TRUE(Visitor.runOver( | 
|  | "template<typename T> int A();\n" | 
|  | "int k = A<int>();\n")); | 
|  | } | 
|  |  | 
|  | TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) { | 
|  | NamedDeclVisitor Visitor; | 
|  | Visitor.ExpectMatch("A<int>::B<char>", 2, 35); | 
|  | EXPECT_TRUE(Visitor.runOver( | 
|  | "template<typename T> struct A {\n" | 
|  | "  template<typename U> static int B();\n" | 
|  | "};\n" | 
|  | "int k = A<int>::B<char>();\n")); | 
|  | } | 
|  |  | 
|  | TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) { | 
|  | // From cfe-commits/Week-of-Mon-20100830/033977.html | 
|  | NamedDeclVisitor Visitor; | 
|  | Visitor.ExpectMatch("vector_iterator<int>", 2, 7); | 
|  | EXPECT_TRUE(Visitor.runOver( | 
|  | "template<typename Container>\n" | 
|  | "class vector_iterator {\n" | 
|  | "    template <typename C> friend class vector_iterator;\n" | 
|  | "};\n" | 
|  | "vector_iterator<int> it_int;\n")); | 
|  | } | 
|  |  | 
|  | } // end anonymous namespace |