1 | //===- unittest/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp ------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "TestVisitor.h" |
10 | |
11 | using namespace clang; |
12 | |
13 | namespace { |
14 | |
15 | class VarDeclVisitor : public ExpectedLocationVisitor { |
16 | public: |
17 | bool VisitVarDecl(VarDecl *Variable) override { |
18 | Match(Name: Variable->getNameAsString(), Location: Variable->getBeginLoc()); |
19 | return true; |
20 | } |
21 | }; |
22 | |
23 | TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) { |
24 | VarDeclVisitor Visitor; |
25 | Visitor.ExpectMatch("i" , 2, 17); |
26 | EXPECT_TRUE(Visitor.runOver( |
27 | "int x[5];\n" |
28 | "void f() { for (int i : x) {} }" , |
29 | VarDeclVisitor::Lang_CXX11)); |
30 | } |
31 | |
32 | class ParmVarDeclVisitorForImplicitCode : public ExpectedLocationVisitor { |
33 | public: |
34 | ParmVarDeclVisitorForImplicitCode() { ShouldVisitImplicitCode = true; } |
35 | |
36 | bool VisitParmVarDecl(ParmVarDecl *ParamVar) override { |
37 | Match(Name: ParamVar->getNameAsString(), Location: ParamVar->getBeginLoc()); |
38 | return true; |
39 | } |
40 | }; |
41 | |
42 | // Test RAV visits parameter variable declaration of the implicit |
43 | // copy assignment operator and implicit copy constructor. |
44 | TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) { |
45 | ParmVarDeclVisitorForImplicitCode Visitor; |
46 | // Match parameter variable name of implicit copy assignment operator and |
47 | // implicit copy constructor. |
48 | // This parameter name does not have a valid IdentifierInfo, and shares |
49 | // same SourceLocation with its class declaration, so we match an empty name |
50 | // with the class' source location. |
51 | Visitor.ExpectMatch("" , 1, 7); |
52 | Visitor.ExpectMatch("" , 3, 7); |
53 | EXPECT_TRUE(Visitor.runOver( |
54 | "class X {};\n" |
55 | "void foo(X a, X b) {a = b;}\n" |
56 | "class Y {};\n" |
57 | "void bar(Y a) {Y b = a;}" )); |
58 | } |
59 | |
60 | class NamedDeclVisitor : public ExpectedLocationVisitor { |
61 | public: |
62 | bool VisitNamedDecl(NamedDecl *Decl) override { |
63 | std::string NameWithTemplateArgs; |
64 | llvm::raw_string_ostream OS(NameWithTemplateArgs); |
65 | Decl->getNameForDiagnostic(OS, |
66 | Policy: Decl->getASTContext().getPrintingPolicy(), |
67 | Qualified: true); |
68 | Match(Name: NameWithTemplateArgs, Location: Decl->getLocation()); |
69 | return true; |
70 | } |
71 | }; |
72 | |
73 | TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) { |
74 | // From cfe-commits/Week-of-Mon-20100830/033998.html |
75 | // Contrary to the approach suggested in that email, we visit all |
76 | // specializations when we visit the primary template. Visiting them when we |
77 | // visit the associated specialization is problematic for specializations of |
78 | // template members of class templates. |
79 | NamedDeclVisitor Visitor; |
80 | Visitor.ExpectMatch("A<bool>" , 1, 26); |
81 | Visitor.ExpectMatch("A<char *>" , 2, 26); |
82 | EXPECT_TRUE(Visitor.runOver( |
83 | "template <class T> class A {};\n" |
84 | "template <class T> class A<T*> {};\n" |
85 | "A<bool> ab;\n" |
86 | "A<char*> acp;\n" )); |
87 | } |
88 | |
89 | TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) { |
90 | NamedDeclVisitor Visitor; |
91 | Visitor.ExpectMatch("A<int>" , 1, 29); |
92 | EXPECT_TRUE(Visitor.runOver( |
93 | "template<typename T> struct A;\n" |
94 | "A<int> *p;\n" )); |
95 | } |
96 | |
97 | TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) { |
98 | NamedDeclVisitor Visitor; |
99 | Visitor.ExpectMatch("A<int>::B<char>" , 2, 31); |
100 | EXPECT_TRUE(Visitor.runOver( |
101 | "template<typename T> struct A {\n" |
102 | " template<typename U> struct B;\n" |
103 | "};\n" |
104 | "A<int>::B<char> *p;\n" )); |
105 | } |
106 | |
107 | TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) { |
108 | NamedDeclVisitor Visitor; |
109 | Visitor.ExpectMatch("A<int>" , 1, 26); |
110 | EXPECT_TRUE(Visitor.runOver( |
111 | "template<typename T> int A();\n" |
112 | "int k = A<int>();\n" )); |
113 | } |
114 | |
115 | TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) { |
116 | NamedDeclVisitor Visitor; |
117 | Visitor.ExpectMatch("A<int>::B<char>" , 2, 35); |
118 | EXPECT_TRUE(Visitor.runOver( |
119 | "template<typename T> struct A {\n" |
120 | " template<typename U> static int B();\n" |
121 | "};\n" |
122 | "int k = A<int>::B<char>();\n" )); |
123 | } |
124 | |
125 | TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) { |
126 | // From cfe-commits/Week-of-Mon-20100830/033977.html |
127 | NamedDeclVisitor Visitor; |
128 | Visitor.ExpectMatch("vector_iterator<int>" , 2, 7); |
129 | EXPECT_TRUE(Visitor.runOver( |
130 | "template<typename Container>\n" |
131 | "class vector_iterator {\n" |
132 | " template <typename C> friend class vector_iterator;\n" |
133 | "};\n" |
134 | "vector_iterator<int> it_int;\n" )); |
135 | } |
136 | |
137 | } // end anonymous namespace |
138 | |