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

source code of clang-tools-extra/clangd/unittests/SymbolInfoTests.cpp