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