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 }
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

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