xref: /llvm-project/clang-tools-extra/clangd/unittests/SymbolInfoTests.cpp (revision f71ffd3b735b4d6ae3c12be1806cdd6205b3b378)
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 
TEST(SymbolInfoTests,All)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{"foo", "", "c:@F@foo#", "decl"}}},
42           {
43               R"cpp( // Simple function reference - definition
44           void $def[[foo]]() {}
45           int bar() {
46             fo^o();
47           }
48         )cpp",
49               {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "def", "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{"foo", "", "c:@F@foo#", "decl", "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{"Foo", "", "c:objc(cs)Foo", "decl",
68                                      "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{"foo", "Foo::", "c:objc(cs)Foo(im)foo",
79                                      "decl", "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{"foo", "bar::", "c:@N@bar@F@foo#",
90                                      "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{"foo", "bar::", "c:@N@bar@F@foo#",
103                                      "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{"foo", "", "c:@F@foo#", "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{"foo", "(anonymous)",
128                                      "c:TestTU.cpp@aN@F@foo#", "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                   "foo", "bar::", "c:@N@bar@F@foo#&1$@N@bar@S@BarType#",
144                   "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{"value", "", "c:@value", "def", "def"}}},
154           {
155               R"cpp( // Local value reference
156           void foo() { int $def[[aaa]]; int bbb = aa^a; }
157         )cpp",
158               {ExpectedSymbolDetails{"aaa", "foo", "c:TestTU.cpp@49@F@foo#@aaa",
159                                      "def", "def"}}},
160           {
161               R"cpp( // Function param
162           void bar(int $def[[aaa]]) {
163             int bbb = a^aa;
164           }
165         )cpp",
166               {ExpectedSymbolDetails{
167                   "aaa", "bar", "c:TestTU.cpp@38@F@bar#I#@aaa", "def", "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{"ii", "foo", "c:TestTU.cpp@54@F@foo#@ii",
178                                      "def", "def"}}},
179           {
180               R"cpp( // Macro reference
181           #define MACRO 5\nint i = MAC^RO;
182         )cpp",
183               {ExpectedSymbolDetails{"MACRO", "",
184                                      "c:TestTU.cpp@38@macro@MACRO"}}},
185           {
186               R"cpp( // Macro reference
187           #define MACRO 5\nint i = MACRO^;
188         )cpp",
189               {ExpectedSymbolDetails{"MACRO", "",
190                                      "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{"foo", "", "c:@F@foo#", "def", "def"},
201                ExpectedSymbolDetails{"foo", "", "c:@F@foo#b#", "def_bool",
202                                      "def_bool"},
203                ExpectedSymbolDetails{"foo", "", "c:@F@foo#I#", "def_int",
204                                      "def_int"},
205                ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@UD@foo",
206                                      "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{"ff", "func_baz2",
220                                      "c:TestTU.cpp@218@F@func_baz2#@ff", "def",
221                                      "def"}}},
222           {
223               R"cpp( // Type reference - declaration
224           struct $decl[[foo]];
225           void bar(fo^o*);
226         )cpp",
227               {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "decl"}}},
228           {
229               R"cpp( // Type reference - definition
230           struct $def[[foo]] {};
231           void bar(fo^o*);
232         )cpp",
233               {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "def", "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{"foo", "", "c:@S@foo", "def", "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{"TT", "bar::", "c:TestTU.cpp@65", "def",
250                                      "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{"NN", "bar::", "c:TestTU.cpp@65", "def",
258                                      "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{"aa", "foo::", "c:@S@foo@FI@aa", "def",
270                                      "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{"aa", "foo::", "c:@S@foo@FI@aa", "def",
281                                      "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{"aa", "foo::", "c:@S@foo@F@aa#", "def",
293                                      "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{"aa", "foo::", "c:@S@foo@F@aa#", "def",
304                                      "def"}}},
305           {
306               R"cpp( // Typedef
307           typedef int $decl[[foo]];
308           void bar() {
309             fo^o a;
310           }
311         )cpp",
312               {ExpectedSymbolDetails{"foo", "", "c:TestTU.cpp@T@foo", "decl"}}},
313           {
314               R"cpp( // Type alias
315           using $decl[[foo]] = int;
316           void bar() {
317             fo^o a;
318           }
319         )cpp",
320               {ExpectedSymbolDetails{"foo", "", "c:@foo", "decl"}}},
321           {
322               R"cpp( // Namespace reference
323           namespace $decl[[foo]] {}
324           using namespace fo^o;
325         )cpp",
326               {ExpectedSymbolDetails{"foo", "", "c:@N@foo", "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{"bar", "foo", "c:@E@foo@bar", "def",
335                                      "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{"bar", "foo::", "c:@E@foo@bar", "def",
344                                      "def"}}},
345           {
346               R"cpp( // Parameters in declarations
347           void foo(int $def[[ba^r]]);
348         )cpp",
349               {ExpectedSymbolDetails{
350                   "bar", "foo", "c:TestTU.cpp@50@F@foo#I#@bar", "def", "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("-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{URIForFile::canonicalize(testPath(TU.Filename), ""),
383                         TestInput.range(Sym.DeclMarker)};
384       if (Sym.DefMarker)
385         Def = Location{URIForFile::canonicalize(testPath(TU.Filename), ""),
386                        TestInput.range(Sym.DefMarker)};
387       Expected.push_back(
388           {Sym.Name, Sym.Container, Sym.USR, SymbolID(Sym.USR), Decl, 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