1 | //===-- SymbolInfoTests.cpp -----------------------*- C++ -*--------------===// |
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 | #include "Annotations.h" |
9 | #include "ParsedAST.h" |
10 | #include "TestTU.h" |
11 | #include "XRefs.h" |
12 | #include "gmock/gmock.h" |
13 | #include "gtest/gtest.h" |
14 | #include <optional> |
15 | |
16 | namespace clang { |
17 | namespace clangd { |
18 | namespace { |
19 | |
20 | using ::testing::UnorderedElementsAreArray; |
21 | |
22 | // Partial SymbolDetails with the rest filled in at testing time. |
23 | struct ExpectedSymbolDetails { |
24 | std::string Name; |
25 | std::string Container; |
26 | std::string USR; |
27 | const char *DeclMarker = nullptr; |
28 | const char *DefMarker = nullptr; |
29 | }; |
30 | |
31 | TEST(SymbolInfoTests, All) { |
32 | std::pair<const char *, std::vector<ExpectedSymbolDetails>> |
33 | TestInputExpectedOutput[] = { |
34 | { |
35 | R"cpp( // Simple function reference - declaration |
36 | void $decl[[foo]](); |
37 | int bar() { |
38 | fo^o(); |
39 | } |
40 | )cpp" , |
41 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@F@foo#" , .DeclMarker: "decl" }}}, |
42 | { |
43 | R"cpp( // Simple function reference - definition |
44 | void $def[[foo]]() {} |
45 | int bar() { |
46 | fo^o(); |
47 | } |
48 | )cpp" , |
49 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@F@foo#" , .DeclMarker: "def" , .DefMarker: "def" }}}, |
50 | { |
51 | R"cpp( // Simple function reference - decl and def |
52 | void $decl[[foo]](); |
53 | void $def[[foo]]() {} |
54 | int bar() { |
55 | fo^o(); |
56 | } |
57 | )cpp" , |
58 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@F@foo#" , .DeclMarker: "decl" , .DefMarker: "def" }}}, |
59 | { |
60 | R"cpp( // Simple class reference - decl and def |
61 | @interface $decl[[Foo]] |
62 | @end |
63 | @implementation $def[[Foo]] |
64 | @end |
65 | void doSomething(F^oo *obj) {} |
66 | )cpp" , |
67 | {ExpectedSymbolDetails{.Name: "Foo" , .Container: "" , .USR: "c:objc(cs)Foo" , .DeclMarker: "decl" , |
68 | .DefMarker: "def" }}}, |
69 | { |
70 | R"cpp( // Simple method reference - decl and def |
71 | @interface Foo |
72 | - (void)$decl[[foo]]; |
73 | @end |
74 | @implementation Foo |
75 | - (void)$def[[fo^o]] {} |
76 | @end |
77 | )cpp" , |
78 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "Foo::" , .USR: "c:objc(cs)Foo(im)foo" , |
79 | .DeclMarker: "decl" , .DefMarker: "def" }}}, |
80 | { |
81 | R"cpp( // Function in namespace reference |
82 | namespace bar { |
83 | void $decl[[foo]](); |
84 | int baz() { |
85 | fo^o(); |
86 | } |
87 | } |
88 | )cpp" , |
89 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "bar::" , .USR: "c:@N@bar@F@foo#" , |
90 | .DeclMarker: "decl" }}}, |
91 | { |
92 | R"cpp( // Function in different namespace reference |
93 | namespace bar { |
94 | void $decl[[foo]](); |
95 | } |
96 | namespace barbar { |
97 | int baz() { |
98 | bar::fo^o(); |
99 | } |
100 | } |
101 | )cpp" , |
102 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "bar::" , .USR: "c:@N@bar@F@foo#" , |
103 | .DeclMarker: "decl" }}}, |
104 | { |
105 | R"cpp( // Function in global namespace reference |
106 | void $decl[[foo]](); |
107 | namespace Nbar { |
108 | namespace Nbaz { |
109 | int baz() { |
110 | ::fo^o(); |
111 | } |
112 | } |
113 | } |
114 | )cpp" , |
115 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@F@foo#" , .DeclMarker: "decl" }}}, |
116 | { |
117 | R"cpp( // Function in anonymous namespace reference |
118 | namespace { |
119 | void $decl[[foo]](); |
120 | } |
121 | namespace barbar { |
122 | int baz() { |
123 | fo^o(); |
124 | } |
125 | } |
126 | )cpp" , |
127 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "(anonymous)" , |
128 | .USR: "c:TestTU.cpp@aN@F@foo#" , .DeclMarker: "decl" }}}, |
129 | { |
130 | R"cpp( // Function reference - ADL |
131 | namespace bar { |
132 | struct BarType {}; |
133 | void $decl[[foo]](const BarType&); |
134 | } |
135 | namespace barbar { |
136 | int baz() { |
137 | bar::BarType b; |
138 | fo^o(b); |
139 | } |
140 | } |
141 | )cpp" , |
142 | {ExpectedSymbolDetails{ |
143 | .Name: "foo" , .Container: "bar::" , .USR: "c:@N@bar@F@foo#&1$@N@bar@S@BarType#" , |
144 | .DeclMarker: "decl" }}}, |
145 | { |
146 | R"cpp( // Global value reference |
147 | int $def[[value]]; |
148 | void foo(int) { } |
149 | void bar() { |
150 | foo(val^ue); |
151 | } |
152 | )cpp" , |
153 | {ExpectedSymbolDetails{.Name: "value" , .Container: "" , .USR: "c:@value" , .DeclMarker: "def" , .DefMarker: "def" }}}, |
154 | { |
155 | R"cpp( // Local value reference |
156 | void foo() { int $def[[aaa]]; int bbb = aa^a; } |
157 | )cpp" , |
158 | {ExpectedSymbolDetails{.Name: "aaa" , .Container: "foo" , .USR: "c:TestTU.cpp@49@F@foo#@aaa" , |
159 | .DeclMarker: "def" , .DefMarker: "def" }}}, |
160 | { |
161 | R"cpp( // Function param |
162 | void bar(int $def[[aaa]]) { |
163 | int bbb = a^aa; |
164 | } |
165 | )cpp" , |
166 | {ExpectedSymbolDetails{ |
167 | .Name: "aaa" , .Container: "bar" , .USR: "c:TestTU.cpp@38@F@bar#I#@aaa" , .DeclMarker: "def" , .DefMarker: "def" }}}, |
168 | { |
169 | R"cpp( // Lambda capture |
170 | void foo() { |
171 | int $def[[ii]]; |
172 | auto lam = [ii]() { |
173 | return i^i; |
174 | }; |
175 | } |
176 | )cpp" , |
177 | {ExpectedSymbolDetails{.Name: "ii" , .Container: "foo" , .USR: "c:TestTU.cpp@54@F@foo#@ii" , |
178 | .DeclMarker: "def" , .DefMarker: "def" }}}, |
179 | { |
180 | R"cpp( // Macro reference |
181 | #define MACRO 5\nint i = MAC^RO; |
182 | )cpp" , |
183 | {ExpectedSymbolDetails{.Name: "MACRO" , .Container: "" , |
184 | .USR: "c:TestTU.cpp@38@macro@MACRO" }}}, |
185 | { |
186 | R"cpp( // Macro reference |
187 | #define MACRO 5\nint i = MACRO^; |
188 | )cpp" , |
189 | {ExpectedSymbolDetails{.Name: "MACRO" , .Container: "" , |
190 | .USR: "c:TestTU.cpp@38@macro@MACRO" }}}, |
191 | { |
192 | R"cpp( // Multiple symbols returned - using overloaded function name |
193 | void $def[[foo]]() {} |
194 | void $def_bool[[foo]](bool) {} |
195 | void $def_int[[foo]](int) {} |
196 | namespace bar { |
197 | using ::$decl[[fo^o]]; |
198 | } |
199 | )cpp" , |
200 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@F@foo#" , .DeclMarker: "def" , .DefMarker: "def" }, |
201 | ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@F@foo#b#" , .DeclMarker: "def_bool" , |
202 | .DefMarker: "def_bool" }, |
203 | ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@F@foo#I#" , .DeclMarker: "def_int" , |
204 | .DefMarker: "def_int" }, |
205 | ExpectedSymbolDetails{.Name: "foo" , .Container: "bar::" , .USR: "c:@N@bar@UD@foo" , |
206 | .DeclMarker: "decl" }}}, |
207 | { |
208 | R"cpp( // Multiple symbols returned - implicit conversion |
209 | struct foo {}; |
210 | struct bar { |
211 | bar(const foo&) {} |
212 | }; |
213 | void func_baz1(bar) {} |
214 | void func_baz2() { |
215 | foo $def[[ff]]; |
216 | func_baz1(f^f); |
217 | } |
218 | )cpp" , |
219 | {ExpectedSymbolDetails{.Name: "ff" , .Container: "func_baz2" , |
220 | .USR: "c:TestTU.cpp@218@F@func_baz2#@ff" , .DeclMarker: "def" , |
221 | .DefMarker: "def" }}}, |
222 | { |
223 | R"cpp( // Type reference - declaration |
224 | struct $decl[[foo]]; |
225 | void bar(fo^o*); |
226 | )cpp" , |
227 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@S@foo" , .DeclMarker: "decl" }}}, |
228 | { |
229 | R"cpp( // Type reference - definition |
230 | struct $def[[foo]] {}; |
231 | void bar(fo^o*); |
232 | )cpp" , |
233 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@S@foo" , .DeclMarker: "def" , .DefMarker: "def" }}}, |
234 | { |
235 | R"cpp( // Type Reference - template argument |
236 | struct $def[[foo]] {}; |
237 | template<class T> struct bar {}; |
238 | void baz() { |
239 | bar<fo^o> b; |
240 | } |
241 | )cpp" , |
242 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@S@foo" , .DeclMarker: "def" , .DefMarker: "def" }}}, |
243 | { |
244 | R"cpp( // Template parameter reference - type param |
245 | template<class $def[[TT]]> struct bar { |
246 | T^T t; |
247 | }; |
248 | )cpp" , |
249 | {ExpectedSymbolDetails{.Name: "TT" , .Container: "bar::" , .USR: "c:TestTU.cpp@65" , .DeclMarker: "def" , |
250 | .DefMarker: "def" }}}, |
251 | { |
252 | R"cpp( // Template parameter reference - type param |
253 | template<int $def[[NN]]> struct bar { |
254 | int a = N^N; |
255 | }; |
256 | )cpp" , |
257 | {ExpectedSymbolDetails{.Name: "NN" , .Container: "bar::" , .USR: "c:TestTU.cpp@65" , .DeclMarker: "def" , |
258 | .DefMarker: "def" }}}, |
259 | { |
260 | R"cpp( // Class member reference - objec |
261 | struct foo { |
262 | int $def[[aa]]; |
263 | }; |
264 | void bar() { |
265 | foo f; |
266 | f.a^a; |
267 | } |
268 | )cpp" , |
269 | {ExpectedSymbolDetails{.Name: "aa" , .Container: "foo::" , .USR: "c:@S@foo@FI@aa" , .DeclMarker: "def" , |
270 | .DefMarker: "def" }}}, |
271 | { |
272 | R"cpp( // Class member reference - pointer |
273 | struct foo { |
274 | int $def[[aa]]; |
275 | }; |
276 | void bar() { |
277 | &foo::a^a; |
278 | } |
279 | )cpp" , |
280 | {ExpectedSymbolDetails{.Name: "aa" , .Container: "foo::" , .USR: "c:@S@foo@FI@aa" , .DeclMarker: "def" , |
281 | .DefMarker: "def" }}}, |
282 | { |
283 | R"cpp( // Class method reference - objec |
284 | struct foo { |
285 | void $def[[aa]]() {} |
286 | }; |
287 | void bar() { |
288 | foo f; |
289 | f.a^a(); |
290 | } |
291 | )cpp" , |
292 | {ExpectedSymbolDetails{.Name: "aa" , .Container: "foo::" , .USR: "c:@S@foo@F@aa#" , .DeclMarker: "def" , |
293 | .DefMarker: "def" }}}, |
294 | { |
295 | R"cpp( // Class method reference - pointer |
296 | struct foo { |
297 | void $def[[aa]]() {} |
298 | }; |
299 | void bar() { |
300 | &foo::a^a; |
301 | } |
302 | )cpp" , |
303 | {ExpectedSymbolDetails{.Name: "aa" , .Container: "foo::" , .USR: "c:@S@foo@F@aa#" , .DeclMarker: "def" , |
304 | .DefMarker: "def" }}}, |
305 | { |
306 | R"cpp( // Typedef |
307 | typedef int $decl[[foo]]; |
308 | void bar() { |
309 | fo^o a; |
310 | } |
311 | )cpp" , |
312 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:TestTU.cpp@T@foo" , .DeclMarker: "decl" }}}, |
313 | { |
314 | R"cpp( // Type alias |
315 | using $decl[[foo]] = int; |
316 | void bar() { |
317 | fo^o a; |
318 | } |
319 | )cpp" , |
320 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@foo" , .DeclMarker: "decl" }}}, |
321 | { |
322 | R"cpp( // Namespace reference |
323 | namespace $decl[[foo]] {} |
324 | using namespace fo^o; |
325 | )cpp" , |
326 | {ExpectedSymbolDetails{.Name: "foo" , .Container: "" , .USR: "c:@N@foo" , .DeclMarker: "decl" }}}, |
327 | { |
328 | R"cpp( // Enum value reference |
329 | enum foo { $def[[bar]], baz }; |
330 | void f() { |
331 | foo fff = ba^r; |
332 | } |
333 | )cpp" , |
334 | {ExpectedSymbolDetails{.Name: "bar" , .Container: "foo" , .USR: "c:@E@foo@bar" , .DeclMarker: "def" , |
335 | .DefMarker: "def" }}}, |
336 | { |
337 | R"cpp( // Enum class value reference |
338 | enum class foo { $def[[bar]], baz }; |
339 | void f() { |
340 | foo fff = foo::ba^r; |
341 | } |
342 | )cpp" , |
343 | {ExpectedSymbolDetails{.Name: "bar" , .Container: "foo::" , .USR: "c:@E@foo@bar" , .DeclMarker: "def" , |
344 | .DefMarker: "def" }}}, |
345 | { |
346 | R"cpp( // Parameters in declarations |
347 | void foo(int $def[[ba^r]]); |
348 | )cpp" , |
349 | {ExpectedSymbolDetails{ |
350 | .Name: "bar" , .Container: "foo" , .USR: "c:TestTU.cpp@50@F@foo#I#@bar" , .DeclMarker: "def" , .DefMarker: "def" }}}, |
351 | { |
352 | R"cpp( // Type inference with auto keyword |
353 | struct foo {}; |
354 | foo getfoo() { return foo{}; } |
355 | void f() { |
356 | au^to a = getfoo(); |
357 | } |
358 | )cpp" , |
359 | {/* not implemented */}}, |
360 | { |
361 | R"cpp( // decltype |
362 | struct foo {}; |
363 | void f() { |
364 | foo f; |
365 | declt^ype(f); |
366 | } |
367 | )cpp" , |
368 | {/* not implemented */}}, |
369 | }; |
370 | |
371 | for (const auto &T : TestInputExpectedOutput) { |
372 | Annotations TestInput(T.first); |
373 | TestTU TU; |
374 | TU.Code = std::string(TestInput.code()); |
375 | TU.ExtraArgs.push_back(x: "-xobjective-c++" ); |
376 | auto AST = TU.build(); |
377 | |
378 | std::vector<SymbolDetails> Expected; |
379 | for (const auto &Sym : T.second) { |
380 | std::optional<Location> Decl, Def; |
381 | if (Sym.DeclMarker) |
382 | Decl = Location{.uri: URIForFile::canonicalize(AbsPath: testPath(File: TU.Filename), TUPath: "" ), |
383 | .range: TestInput.range(Name: Sym.DeclMarker)}; |
384 | if (Sym.DefMarker) |
385 | Def = Location{.uri: URIForFile::canonicalize(AbsPath: testPath(File: TU.Filename), TUPath: "" ), |
386 | .range: TestInput.range(Name: Sym.DefMarker)}; |
387 | Expected.push_back( |
388 | x: {.name: Sym.Name, .containerName: Sym.Container, .USR: Sym.USR, .ID: SymbolID(Sym.USR), .declarationRange: Decl, .definitionRange: Def}); |
389 | } |
390 | |
391 | EXPECT_THAT(getSymbolInfo(AST, TestInput.point()), |
392 | UnorderedElementsAreArray(Expected)) |
393 | << T.first; |
394 | } |
395 | } |
396 | |
397 | } // namespace |
398 | } // namespace clangd |
399 | } // namespace clang |
400 | |