1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "TestVisitor.h" |
10 | #include "clang/Tooling/Core/Lookup.h" |
11 | using namespace clang; |
12 | |
13 | namespace { |
14 | struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> { |
15 | std::function<void(CallExpr *)> OnCall; |
16 | std::function<void(RecordTypeLoc)> OnRecordTypeLoc; |
17 | SmallVector<Decl *, 4> DeclStack; |
18 | |
19 | bool VisitCallExpr(CallExpr *Expr) { |
20 | if (OnCall) |
21 | OnCall(Expr); |
22 | return true; |
23 | } |
24 | |
25 | bool VisitRecordTypeLoc(RecordTypeLoc Loc) { |
26 | if (OnRecordTypeLoc) |
27 | OnRecordTypeLoc(Loc); |
28 | return true; |
29 | } |
30 | |
31 | bool TraverseDecl(Decl *D) { |
32 | DeclStack.push_back(D); |
33 | bool Ret = TestVisitor::TraverseDecl(D); |
34 | DeclStack.pop_back(); |
35 | return Ret; |
36 | } |
37 | }; |
38 | |
39 | TEST(LookupTest, replaceNestedFunctionName) { |
40 | GetDeclsVisitor Visitor; |
41 | |
42 | auto replaceCallExpr = [&](const CallExpr *Expr, |
43 | StringRef ReplacementString) { |
44 | const auto *Callee = cast<DeclRefExpr>(Expr->getCallee()->IgnoreImplicit()); |
45 | const ValueDecl *FD = Callee->getDecl(); |
46 | return tooling::replaceNestedName( |
47 | Callee->getQualifier(), Visitor.DeclStack.back()->getDeclContext(), FD, |
48 | ReplacementString); |
49 | }; |
50 | |
51 | Visitor.OnCall = [&](CallExpr *Expr) { |
52 | EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); |
53 | }; |
54 | Visitor.runOver("namespace a { void foo(); }\n" |
55 | "namespace a { void f() { foo(); } }\n"); |
56 | |
57 | Visitor.OnCall = [&](CallExpr *Expr) { |
58 | EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); |
59 | }; |
60 | Visitor.runOver("namespace a { void foo(); }\n" |
61 | "namespace a { void f() { foo(); } }\n"); |
62 | |
63 | Visitor.OnCall = [&](CallExpr *Expr) { |
64 | EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); |
65 | }; |
66 | Visitor.runOver("namespace a { void foo(); }\n" |
67 | "namespace b { void f() { a::foo(); } }\n"); |
68 | |
69 | Visitor.OnCall = [&](CallExpr *Expr) { |
70 | EXPECT_EQ("::a::bar", replaceCallExpr(Expr, "::a::bar")); |
71 | }; |
72 | Visitor.runOver("namespace a { void foo(); }\n" |
73 | "namespace b { namespace a { void foo(); }\n" |
74 | "void f() { a::foo(); } }\n"); |
75 | |
76 | Visitor.OnCall = [&](CallExpr *Expr) { |
77 | EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); |
78 | }; |
79 | Visitor.runOver("namespace a { namespace b { void foo(); }\n" |
80 | "void f() { b::foo(); } }\n"); |
81 | |
82 | Visitor.OnCall = [&](CallExpr *Expr) { |
83 | EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); |
84 | }; |
85 | Visitor.runOver("namespace a { namespace b { void foo(); }\n" |
86 | "void f() { b::foo(); } }\n"); |
87 | |
88 | Visitor.OnCall = [&](CallExpr *Expr) { |
89 | EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); |
90 | }; |
91 | Visitor.runOver("void foo(); void f() { foo(); }\n"); |
92 | |
93 | Visitor.OnCall = [&](CallExpr *Expr) { |
94 | EXPECT_EQ("::bar", replaceCallExpr(Expr, "::bar")); |
95 | }; |
96 | Visitor.runOver("void foo(); void f() { ::foo(); }\n"); |
97 | |
98 | Visitor.OnCall = [&](CallExpr *Expr) { |
99 | EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); |
100 | }; |
101 | Visitor.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n"); |
102 | |
103 | Visitor.OnCall = [&](CallExpr *Expr) { |
104 | EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); |
105 | }; |
106 | Visitor.runOver("namespace a { int foo(); }\nauto f = a::foo();\n"); |
107 | |
108 | Visitor.OnCall = [&](CallExpr *Expr) { |
109 | EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); |
110 | }; |
111 | Visitor.runOver( |
112 | "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n"); |
113 | |
114 | Visitor.OnCall = [&](CallExpr *Expr) { |
115 | EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); |
116 | }; |
117 | Visitor.runOver("namespace a { namespace b { void foo(); } }\n" |
118 | "namespace a { namespace b { namespace {" |
119 | "void f() { foo(); }" |
120 | "} } }\n"); |
121 | |
122 | Visitor.OnCall = [&](CallExpr *Expr) { |
123 | EXPECT_EQ("x::bar", replaceCallExpr(Expr, "::a::x::bar")); |
124 | }; |
125 | Visitor.runOver("namespace a { namespace b { void foo(); } }\n" |
126 | "namespace a { namespace b { namespace c {" |
127 | "void f() { foo(); }" |
128 | "} } }\n"); |
129 | |
130 | |
131 | Visitor.OnCall = [&](CallExpr *Expr) { |
132 | EXPECT_EQ("a::y::bar", replaceCallExpr(Expr, "::a::y::bar")); |
133 | }; |
134 | Visitor.runOver(R"( |
135 | namespace a { |
136 | namespace b { |
137 | namespace x { void foo() {} } |
138 | namespace y { void foo() {} } |
139 | } |
140 | } |
141 | |
142 | namespace a { |
143 | namespace b { |
144 | void f() { x::foo(); } |
145 | } |
146 | })"); |
147 | |
148 | Visitor.OnCall = [&](CallExpr *Expr) { |
149 | |
150 | EXPECT_EQ("::y::bar", replaceCallExpr(Expr, "::y::bar")); |
151 | }; |
152 | Visitor.runOver(R"( |
153 | namespace a { |
154 | namespace b { |
155 | void foo() {} |
156 | namespace y { } |
157 | } |
158 | } |
159 | |
160 | namespace a { |
161 | namespace b { |
162 | void f() { foo(); } |
163 | } |
164 | })"); |
165 | |
166 | Visitor.OnCall = [&](CallExpr *Expr) { |
167 | EXPECT_EQ("y::bar", replaceCallExpr(Expr, "::y::bar")); |
168 | }; |
169 | Visitor.runOver(R"( |
170 | namespace a { |
171 | namespace b { |
172 | namespace x { void foo() {} } |
173 | namespace y { void foo() {} } |
174 | } |
175 | } |
176 | |
177 | void f() { a::b::x::foo(); } |
178 | )"); |
179 | } |
180 | |
181 | TEST(LookupTest, replaceNestedClassName) { |
182 | GetDeclsVisitor Visitor; |
183 | |
184 | auto replaceRecordTypeLoc = [&](RecordTypeLoc Loc, |
185 | StringRef ReplacementString) { |
186 | const auto *FD = cast<CXXRecordDecl>(Loc.getDecl()); |
187 | return tooling::replaceNestedName( |
188 | nullptr, Visitor.DeclStack.back()->getDeclContext(), FD, |
189 | ReplacementString); |
190 | }; |
191 | |
192 | Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) { |
193 | |
194 | |
195 | if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") { |
196 | EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar")); |
197 | } |
198 | }; |
199 | Visitor.runOver("namespace a { namespace b {\n" |
200 | "class Foo;\n" |
201 | "namespace c { Foo f();; }\n" |
202 | "} }\n"); |
203 | |
204 | Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) { |
205 | |
206 | |
207 | |
208 | if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") { |
209 | EXPECT_EQ("Bar", replaceRecordTypeLoc(Type, "::a::x::Bar")); |
210 | } |
211 | }; |
212 | Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n" |
213 | "namespace c { using a::b::Foo; Foo f();; }\n"); |
214 | } |
215 | |
216 | } |
217 | |