xref: /llvm-project/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp (revision d1aec79a2ce077e49da7699c4ca2dee239d0a249)
1 //===-- FindSymbolsTests.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 "FindSymbols.h"
10 #include "TestFS.h"
11 #include "TestTU.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15 
16 namespace clang {
17 namespace clangd {
18 
19 namespace {
20 
21 using ::testing::AllOf;
22 using ::testing::ElementsAre;
23 using ::testing::ElementsAreArray;
24 using ::testing::Field;
25 using ::testing::IsEmpty;
26 using ::testing::UnorderedElementsAre;
27 
28 // GMock helpers for matching SymbolInfos items.
29 MATCHER_P(qName, Name, "") {
30   if (arg.containerName.empty())
31     return arg.name == Name;
32   return (arg.containerName + "::" + arg.name) == Name;
33 }
34 MATCHER_P(withName, N, "") { return arg.name == N; }
35 MATCHER_P(withKind, Kind, "") { return arg.kind == Kind; }
36 MATCHER_P(withDetail, Detail, "") { return arg.detail == Detail; }
37 MATCHER_P(symRange, Range, "") { return arg.range == Range; }
38 
39 // GMock helpers for matching DocumentSymbol.
40 MATCHER_P(symNameRange, Range, "") { return arg.selectionRange == Range; }
41 template <class... ChildMatchers>
children(ChildMatchers...ChildrenM)42 ::testing::Matcher<DocumentSymbol> children(ChildMatchers... ChildrenM) {
43   return Field(&DocumentSymbol::children, UnorderedElementsAre(ChildrenM...));
44 }
45 
getSymbols(TestTU & TU,llvm::StringRef Query,int Limit=0)46 std::vector<SymbolInformation> getSymbols(TestTU &TU, llvm::StringRef Query,
47                                           int Limit = 0) {
48   auto SymbolInfos = getWorkspaceSymbols(Query, Limit, TU.index().get(),
49                                          testPath(TU.Filename));
50   EXPECT_TRUE(bool(SymbolInfos)) << "workspaceSymbols returned an error";
51   return *SymbolInfos;
52 }
53 
TEST(WorkspaceSymbols,Macros)54 TEST(WorkspaceSymbols, Macros) {
55   TestTU TU;
56   TU.Code = R"cpp(
57        #define MACRO X
58        )cpp";
59 
60   // LSP's SymbolKind doesn't have a "Macro" kind, and
61   // indexSymbolKindToSymbolKind() currently maps macros
62   // to SymbolKind::String.
63   EXPECT_THAT(getSymbols(TU, "macro"),
64               ElementsAre(AllOf(qName("MACRO"), withKind(SymbolKind::String))));
65 }
66 
TEST(WorkspaceSymbols,NoLocals)67 TEST(WorkspaceSymbols, NoLocals) {
68   TestTU TU;
69   TU.Code = R"cpp(
70       void test(int FirstParam, int SecondParam) {
71         struct LocalClass {};
72         int local_var;
73       })cpp";
74   EXPECT_THAT(getSymbols(TU, "l"), ElementsAre(qName("LocalClass")));
75   EXPECT_THAT(getSymbols(TU, "p"), IsEmpty());
76 }
77 
TEST(WorkspaceSymbols,Globals)78 TEST(WorkspaceSymbols, Globals) {
79   TestTU TU;
80   TU.AdditionalFiles["foo.h"] = R"cpp(
81       int global_var;
82 
83       int global_func();
84 
85       struct GlobalStruct {};)cpp";
86   TU.Code = R"cpp(
87       #include "foo.h"
88       )cpp";
89   EXPECT_THAT(getSymbols(TU, "global"),
90               UnorderedElementsAre(
91                   AllOf(qName("GlobalStruct"), withKind(SymbolKind::Struct)),
92                   AllOf(qName("global_func"), withKind(SymbolKind::Function)),
93                   AllOf(qName("global_var"), withKind(SymbolKind::Variable))));
94 }
95 
TEST(WorkspaceSymbols,Unnamed)96 TEST(WorkspaceSymbols, Unnamed) {
97   TestTU TU;
98   TU.AdditionalFiles["foo.h"] = R"cpp(
99       struct {
100         int InUnnamed;
101       } UnnamedStruct;)cpp";
102   TU.Code = R"cpp(
103       #include "foo.h"
104       )cpp";
105   EXPECT_THAT(getSymbols(TU, "UnnamedStruct"),
106               ElementsAre(AllOf(qName("UnnamedStruct"),
107                                 withKind(SymbolKind::Variable))));
108   EXPECT_THAT(getSymbols(TU, "InUnnamed"),
109               ElementsAre(AllOf(qName("(anonymous struct)::InUnnamed"),
110                                 withKind(SymbolKind::Field))));
111 }
112 
TEST(WorkspaceSymbols,InMainFile)113 TEST(WorkspaceSymbols, InMainFile) {
114   TestTU TU;
115   TU.Code = R"cpp(
116       int test() {}
117       static void test2() {}
118       )cpp";
119   EXPECT_THAT(getSymbols(TU, "test"),
120               ElementsAre(qName("test"), qName("test2")));
121 }
122 
TEST(WorkspaceSymbols,Namespaces)123 TEST(WorkspaceSymbols, Namespaces) {
124   TestTU TU;
125   TU.AdditionalFiles["foo.h"] = R"cpp(
126       namespace ans1 {
127         int ai1;
128         namespace ans2 {
129           int ai2;
130           namespace ans3 {
131             int ai3;
132           }
133         }
134       }
135       )cpp";
136   TU.Code = R"cpp(
137       #include "foo.h"
138       )cpp";
139   EXPECT_THAT(getSymbols(TU, "a"),
140               UnorderedElementsAre(
141                   qName("ans1"), qName("ans1::ai1"), qName("ans1::ans2"),
142                   qName("ans1::ans2::ai2"), qName("ans1::ans2::ans3"),
143                   qName("ans1::ans2::ans3::ai3")));
144   EXPECT_THAT(getSymbols(TU, "::"), ElementsAre(qName("ans1")));
145   EXPECT_THAT(getSymbols(TU, "::a"), ElementsAre(qName("ans1")));
146   EXPECT_THAT(getSymbols(TU, "ans1::"),
147               UnorderedElementsAre(qName("ans1::ai1"), qName("ans1::ans2"),
148                                    qName("ans1::ans2::ai2"),
149                                    qName("ans1::ans2::ans3"),
150                                    qName("ans1::ans2::ans3::ai3")));
151   EXPECT_THAT(getSymbols(TU, "ans2::"),
152               UnorderedElementsAre(qName("ans1::ans2::ai2"),
153                                    qName("ans1::ans2::ans3"),
154                                    qName("ans1::ans2::ans3::ai3")));
155   EXPECT_THAT(getSymbols(TU, "::ans1"), ElementsAre(qName("ans1")));
156   EXPECT_THAT(getSymbols(TU, "::ans1::"),
157               UnorderedElementsAre(qName("ans1::ai1"), qName("ans1::ans2")));
158   EXPECT_THAT(getSymbols(TU, "::ans1::ans2"), ElementsAre(qName("ans1::ans2")));
159   EXPECT_THAT(getSymbols(TU, "::ans1::ans2::"),
160               ElementsAre(qName("ans1::ans2::ai2"), qName("ans1::ans2::ans3")));
161 
162   // Ensure sub-sequence matching works.
163   EXPECT_THAT(getSymbols(TU, "ans1::ans3::ai"),
164               UnorderedElementsAre(qName("ans1::ans2::ans3::ai3")));
165 }
166 
TEST(WorkspaceSymbols,AnonymousNamespace)167 TEST(WorkspaceSymbols, AnonymousNamespace) {
168   TestTU TU;
169   TU.Code = R"cpp(
170       namespace {
171       void test() {}
172       }
173       )cpp";
174   EXPECT_THAT(getSymbols(TU, "test"), ElementsAre(qName("test")));
175 }
176 
TEST(WorkspaceSymbols,MultiFile)177 TEST(WorkspaceSymbols, MultiFile) {
178   TestTU TU;
179   TU.AdditionalFiles["foo.h"] = R"cpp(
180       int foo() {
181       }
182       )cpp";
183   TU.AdditionalFiles["foo2.h"] = R"cpp(
184       int foo2() {
185       }
186       )cpp";
187   TU.Code = R"cpp(
188       #include "foo.h"
189       #include "foo2.h"
190       )cpp";
191   EXPECT_THAT(getSymbols(TU, "foo"),
192               UnorderedElementsAre(qName("foo"), qName("foo2")));
193 }
194 
TEST(WorkspaceSymbols,GlobalNamespaceQueries)195 TEST(WorkspaceSymbols, GlobalNamespaceQueries) {
196   TestTU TU;
197   TU.AdditionalFiles["foo.h"] = R"cpp(
198       int foo() {
199       }
200       class Foo {
201         int a;
202       };
203       namespace ns {
204       int foo2() {
205       }
206       }
207       )cpp";
208   TU.Code = R"cpp(
209       #include "foo.h"
210       )cpp";
211   EXPECT_THAT(getSymbols(TU, "::"),
212               UnorderedElementsAre(
213                   AllOf(qName("Foo"), withKind(SymbolKind::Class)),
214                   AllOf(qName("foo"), withKind(SymbolKind::Function)),
215                   AllOf(qName("ns"), withKind(SymbolKind::Namespace))));
216   EXPECT_THAT(getSymbols(TU, ":"), IsEmpty());
217   EXPECT_THAT(getSymbols(TU, ""),
218               UnorderedElementsAre(qName("foo"), qName("Foo"), qName("Foo::a"),
219                                    qName("ns"), qName("ns::foo2")));
220 }
221 
TEST(WorkspaceSymbols,Enums)222 TEST(WorkspaceSymbols, Enums) {
223   TestTU TU;
224   TU.AdditionalFiles["foo.h"] = R"cpp(
225     enum {
226       Red
227     };
228     enum Color {
229       Green
230     };
231     enum class Color2 {
232       Yellow
233     };
234     namespace ns {
235       enum {
236         Black
237       };
238       enum Color3 {
239         Blue
240       };
241       enum class Color4 {
242         White
243       };
244     }
245       )cpp";
246   TU.Code = R"cpp(
247       #include "foo.h"
248       )cpp";
249   EXPECT_THAT(getSymbols(TU, "Red"), ElementsAre(qName("Red")));
250   EXPECT_THAT(getSymbols(TU, "::Red"), ElementsAre(qName("Red")));
251   EXPECT_THAT(getSymbols(TU, "Green"), ElementsAre(qName("Green")));
252   EXPECT_THAT(getSymbols(TU, "Green"), ElementsAre(qName("Green")));
253   EXPECT_THAT(getSymbols(TU, "Color2::Yellow"),
254               ElementsAre(qName("Color2::Yellow")));
255   EXPECT_THAT(getSymbols(TU, "Yellow"), ElementsAre(qName("Color2::Yellow")));
256 
257   EXPECT_THAT(getSymbols(TU, "ns::Black"), ElementsAre(qName("ns::Black")));
258   EXPECT_THAT(getSymbols(TU, "ns::Blue"), ElementsAre(qName("ns::Blue")));
259   EXPECT_THAT(getSymbols(TU, "ns::Color4::White"),
260               ElementsAre(qName("ns::Color4::White")));
261 }
262 
TEST(WorkspaceSymbols,Ranking)263 TEST(WorkspaceSymbols, Ranking) {
264   TestTU TU;
265   TU.AdditionalFiles["foo.h"] = R"cpp(
266       namespace ns{}
267       void func();
268       )cpp";
269   TU.Code = R"cpp(
270       #include "foo.h"
271       )cpp";
272   EXPECT_THAT(getSymbols(TU, "::"), ElementsAre(qName("func"), qName("ns")));
273 }
274 
TEST(WorkspaceSymbols,RankingPartialNamespace)275 TEST(WorkspaceSymbols, RankingPartialNamespace) {
276   TestTU TU;
277   TU.Code = R"cpp(
278     namespace ns1 {
279       namespace ns2 { struct Foo {}; }
280     }
281     namespace ns2 { struct FooB {}; })cpp";
282   EXPECT_THAT(getSymbols(TU, "ns2::f"),
283               ElementsAre(qName("ns2::FooB"), qName("ns1::ns2::Foo")));
284 }
285 
TEST(WorkspaceSymbols,WithLimit)286 TEST(WorkspaceSymbols, WithLimit) {
287   TestTU TU;
288   TU.AdditionalFiles["foo.h"] = R"cpp(
289       int foo;
290       int foo2;
291       )cpp";
292   TU.Code = R"cpp(
293       #include "foo.h"
294       )cpp";
295   // Foo is higher ranked because of exact name match.
296   EXPECT_THAT(getSymbols(TU, "foo"),
297               UnorderedElementsAre(
298                   AllOf(qName("foo"), withKind(SymbolKind::Variable)),
299                   AllOf(qName("foo2"), withKind(SymbolKind::Variable))));
300 
301   EXPECT_THAT(getSymbols(TU, "foo", 1), ElementsAre(qName("foo")));
302 }
303 
TEST(WorkspaceSymbols,TempSpecs)304 TEST(WorkspaceSymbols, TempSpecs) {
305   TestTU TU;
306   TU.ExtraArgs = {"-xc++"};
307   TU.Code = R"cpp(
308       template <typename T, typename U, int X = 5> class Foo {};
309       template <typename T> class Foo<int, T> {};
310       template <> class Foo<bool, int> {};
311       template <> class Foo<bool, int, 3> {};
312       )cpp";
313   // Foo is higher ranked because of exact name match.
314   EXPECT_THAT(
315       getSymbols(TU, "Foo"),
316       UnorderedElementsAre(
317           AllOf(qName("Foo"), withKind(SymbolKind::Class)),
318           AllOf(qName("Foo<int, T>"), withKind(SymbolKind::Class)),
319           AllOf(qName("Foo<bool, int>"), withKind(SymbolKind::Class)),
320           AllOf(qName("Foo<bool, int, 3>"), withKind(SymbolKind::Class))));
321 }
322 
getSymbols(ParsedAST AST)323 std::vector<DocumentSymbol> getSymbols(ParsedAST AST) {
324   auto SymbolInfos = getDocumentSymbols(AST);
325   EXPECT_TRUE(bool(SymbolInfos)) << "documentSymbols returned an error";
326   return *SymbolInfos;
327 }
328 
TEST(DocumentSymbols,BasicSymbols)329 TEST(DocumentSymbols, BasicSymbols) {
330   TestTU TU;
331   Annotations Main(R"(
332       class Foo;
333       class Foo {
334         Foo() {}
335         Foo(int a) {}
336         void $decl[[f]]();
337         friend void f1();
338         friend class Friend;
339         Foo& operator=(const Foo&);
340         ~Foo();
341         class Nested {
342         void f();
343         };
344       };
345       class Friend {
346       };
347 
348       void f1();
349       inline void f2() {}
350       static const int KInt = 2;
351       const char* kStr = "123";
352 
353       void f1() {}
354 
355       namespace foo {
356       // Type alias
357       typedef int int32;
358       using int32_t = int32;
359 
360       // Variable
361       int v1;
362 
363       // Namespace
364       namespace bar {
365       int v2;
366       }
367       // Namespace alias
368       namespace baz = bar;
369 
370       using bar::v2;
371       } // namespace foo
372     )");
373 
374   TU.Code = Main.code().str();
375   EXPECT_THAT(
376       getSymbols(TU.build()),
377       ElementsAreArray(
378           {AllOf(withName("Foo"), withKind(SymbolKind::Class),
379                  withDetail("class"), children()),
380            AllOf(withName("Foo"), withKind(SymbolKind::Class),
381                  withDetail("class"),
382                  children(
383                      AllOf(withName("Foo"), withKind(SymbolKind::Constructor),
384                            withDetail("()"), children()),
385                      AllOf(withName("Foo"), withKind(SymbolKind::Constructor),
386                            withDetail("(int)"), children()),
387                      AllOf(withName("f"), withKind(SymbolKind::Method),
388                            withDetail("void ()"), children()),
389                      AllOf(withName("operator="), withKind(SymbolKind::Method),
390                            withDetail("Foo &(const Foo &)"), children()),
391                      AllOf(withName("~Foo"), withKind(SymbolKind::Constructor),
392                            withDetail(""), children()),
393                      AllOf(withName("Nested"), withKind(SymbolKind::Class),
394                            withDetail("class"),
395                            children(AllOf(
396                                withName("f"), withKind(SymbolKind::Method),
397                                withDetail("void ()"), children()))))),
398            AllOf(withName("Friend"), withKind(SymbolKind::Class),
399                  withDetail("class"), children()),
400            AllOf(withName("f1"), withKind(SymbolKind::Function),
401                  withDetail("void ()"), children()),
402            AllOf(withName("f2"), withKind(SymbolKind::Function),
403                  withDetail("void ()"), children()),
404            AllOf(withName("KInt"), withKind(SymbolKind::Variable),
405                  withDetail("const int"), children()),
406            AllOf(withName("kStr"), withKind(SymbolKind::Variable),
407                  withDetail("const char *"), children()),
408            AllOf(withName("f1"), withKind(SymbolKind::Function),
409                  withDetail("void ()"), children()),
410            AllOf(
411                withName("foo"), withKind(SymbolKind::Namespace), withDetail(""),
412                children(AllOf(withName("int32"), withKind(SymbolKind::Class),
413                               withDetail("type alias"), children()),
414                         AllOf(withName("int32_t"), withKind(SymbolKind::Class),
415                               withDetail("type alias"), children()),
416                         AllOf(withName("v1"), withKind(SymbolKind::Variable),
417                               withDetail("int"), children()),
418                         AllOf(withName("bar"), withKind(SymbolKind::Namespace),
419                               withDetail(""),
420                               children(AllOf(withName("v2"),
421                                              withKind(SymbolKind::Variable),
422                                              withDetail("int"), children()))),
423                         AllOf(withName("baz"), withKind(SymbolKind::Namespace),
424                               withDetail(""), children()),
425                         AllOf(withName("v2"), withKind(SymbolKind::Namespace),
426                               withDetail(""))))}));
427 }
428 
TEST(DocumentSymbols,DeclarationDefinition)429 TEST(DocumentSymbols, DeclarationDefinition) {
430   TestTU TU;
431   Annotations Main(R"(
432       class Foo {
433         void $decl[[f]]();
434       };
435       void Foo::$def[[f]]() {
436       }
437     )");
438 
439   TU.Code = Main.code().str();
440   EXPECT_THAT(
441       getSymbols(TU.build()),
442       ElementsAre(
443           AllOf(withName("Foo"), withKind(SymbolKind::Class),
444                 withDetail("class"),
445                 children(AllOf(withName("f"), withKind(SymbolKind::Method),
446                                withDetail("void ()"),
447                                symNameRange(Main.range("decl"))))),
448           AllOf(withName("Foo::f"), withKind(SymbolKind::Method),
449                 withDetail("void ()"), symNameRange(Main.range("def")))));
450 }
451 
TEST(DocumentSymbols,Concepts)452 TEST(DocumentSymbols, Concepts) {
453   TestTU TU;
454   TU.ExtraArgs = {"-std=c++20"};
455   TU.Code = "template <typename T> concept C = requires(T t) { t.foo(); };";
456 
457   EXPECT_THAT(getSymbols(TU.build()),
458               ElementsAre(AllOf(withName("C"), withDetail("concept"))));
459 }
460 
TEST(DocumentSymbols,ExternSymbol)461 TEST(DocumentSymbols, ExternSymbol) {
462   TestTU TU;
463   TU.AdditionalFiles["foo.h"] = R"cpp(
464       extern int var;
465       )cpp";
466   TU.Code = R"cpp(
467       #include "foo.h"
468       )cpp";
469 
470   EXPECT_THAT(getSymbols(TU.build()), IsEmpty());
471 }
472 
TEST(DocumentSymbols,ExternContext)473 TEST(DocumentSymbols, ExternContext) {
474   TestTU TU;
475   TU.Code = R"cpp(
476       extern "C" {
477       void foo();
478       class Foo {};
479       }
480       namespace ns {
481         extern "C" {
482         void bar();
483         class Bar {};
484         }
485       })cpp";
486 
487   EXPECT_THAT(getSymbols(TU.build()),
488               ElementsAre(withName("foo"), withName("Foo"),
489                           AllOf(withName("ns"),
490                                 children(withName("bar"), withName("Bar")))));
491 }
492 
TEST(DocumentSymbols,ExportContext)493 TEST(DocumentSymbols, ExportContext) {
494   TestTU TU;
495   TU.ExtraArgs = {"-std=c++20"};
496   TU.Code = R"cpp(
497       export module test;
498       export {
499       void foo();
500       class Foo {};
501       })cpp";
502 
503   EXPECT_THAT(getSymbols(TU.build()),
504               ElementsAre(withName("foo"), withName("Foo")));
505 }
506 
TEST(DocumentSymbols,NoLocals)507 TEST(DocumentSymbols, NoLocals) {
508   TestTU TU;
509   TU.Code = R"cpp(
510       void test(int FirstParam, int SecondParam) {
511         struct LocalClass {};
512         int local_var;
513       })cpp";
514   EXPECT_THAT(getSymbols(TU.build()), ElementsAre(withName("test")));
515 }
516 
TEST(DocumentSymbols,Unnamed)517 TEST(DocumentSymbols, Unnamed) {
518   TestTU TU;
519   TU.Code = R"cpp(
520       struct {
521         int InUnnamed;
522       } UnnamedStruct;
523       )cpp";
524   EXPECT_THAT(
525       getSymbols(TU.build()),
526       ElementsAre(AllOf(withName("(anonymous struct)"),
527                         withKind(SymbolKind::Struct), withDetail("struct"),
528                         children(AllOf(withName("InUnnamed"),
529                                        withKind(SymbolKind::Field),
530                                        withDetail("int"), children()))),
531                   AllOf(withName("UnnamedStruct"),
532                         withKind(SymbolKind::Variable),
533                         withDetail("struct (unnamed)"), children())));
534 }
535 
TEST(DocumentSymbols,InHeaderFile)536 TEST(DocumentSymbols, InHeaderFile) {
537   TestTU TU;
538   TU.AdditionalFiles["bar.h"] = R"cpp(
539       int foo() {
540       }
541       )cpp";
542   TU.Code = R"cpp(
543       int i; // declaration to finish preamble
544       #include "bar.h"
545       int test() {
546       }
547       )cpp";
548   EXPECT_THAT(getSymbols(TU.build()),
549               ElementsAre(withName("i"), withName("test")));
550 }
551 
TEST(DocumentSymbols,Template)552 TEST(DocumentSymbols, Template) {
553   TestTU TU;
554   TU.Code = R"(
555     template <class T> struct Tmpl {T x = 0;};
556     template <> struct Tmpl<int> {
557       int y = 0;
558     };
559     extern template struct Tmpl<float>;
560     template struct Tmpl<double>;
561 
562     template <class T, class U, class Z = float>
563     int funcTmpl(U a);
564     template <>
565     int funcTmpl<int>(double a);
566 
567     template <class T, class U = double>
568     int varTmpl = T();
569     template <>
570     double varTmpl<int> = 10.0;
571   )";
572   EXPECT_THAT(
573       getSymbols(TU.build()),
574       ElementsAre(
575           AllOf(withName("Tmpl"), withKind(SymbolKind::Struct),
576                 withDetail("template struct"),
577                 children(AllOf(withName("x"), withKind(SymbolKind::Field),
578                                withDetail("T")))),
579           AllOf(withName("Tmpl<int>"), withKind(SymbolKind::Struct),
580                 withDetail("struct"),
581                 children(AllOf(withName("y"), withDetail("int")))),
582           AllOf(withName("Tmpl<float>"), withKind(SymbolKind::Struct),
583                 withDetail("struct"), children()),
584           AllOf(withName("Tmpl<double>"), withKind(SymbolKind::Struct),
585                 withDetail("struct"), children()),
586           AllOf(withName("funcTmpl"), withDetail("template int (U)"),
587                 children()),
588           AllOf(withName("funcTmpl<int>"), withDetail("int (double)"),
589                 children()),
590           AllOf(withName("varTmpl"), withDetail("template int"), children()),
591           AllOf(withName("varTmpl<int>"), withDetail("double"), children())));
592 }
593 
TEST(DocumentSymbols,Namespaces)594 TEST(DocumentSymbols, Namespaces) {
595   TestTU TU;
596   TU.Code = R"cpp(
597       namespace ans1 {
598         int ai1;
599       namespace ans2 {
600         int ai2;
601       }
602       }
603       namespace {
604       void test() {}
605       }
606 
607       namespace na {
608       inline namespace nb {
609       class Foo {};
610       }
611       }
612       namespace na {
613       // This is still inlined.
614       namespace nb {
615       class Bar {};
616       }
617       }
618       )cpp";
619   EXPECT_THAT(
620       getSymbols(TU.build()),
621       ElementsAreArray<::testing::Matcher<DocumentSymbol>>(
622           {AllOf(withName("ans1"),
623                  children(AllOf(withName("ai1"), children()),
624                           AllOf(withName("ans2"), children(withName("ai2"))))),
625            AllOf(withName("(anonymous namespace)"), children(withName("test"))),
626            AllOf(withName("na"),
627                  children(AllOf(withName("nb"), children(withName("Foo"))))),
628            AllOf(withName("na"),
629                  children(AllOf(withName("nb"), children(withName("Bar")))))}));
630 }
631 
TEST(DocumentSymbols,Enums)632 TEST(DocumentSymbols, Enums) {
633   TestTU TU;
634   TU.Code = R"(
635       enum {
636         Red
637       };
638       enum Color {
639         Green
640       };
641       enum class Color2 {
642         Yellow
643       };
644       namespace ns {
645       enum {
646         Black
647       };
648       }
649     )";
650   EXPECT_THAT(
651       getSymbols(TU.build()),
652       ElementsAre(
653           AllOf(withName("(anonymous enum)"), withDetail("enum"),
654                 children(AllOf(withName("Red"), withDetail("(unnamed)")))),
655           AllOf(withName("Color"), withDetail("enum"),
656                 children(AllOf(withName("Green"), withDetail("Color")))),
657           AllOf(withName("Color2"), withDetail("enum"),
658                 children(AllOf(withName("Yellow"), withDetail("Color2")))),
659           AllOf(withName("ns"),
660                 children(AllOf(withName("(anonymous enum)"), withDetail("enum"),
661                                children(AllOf(withName("Black"),
662                                               withDetail("(unnamed)"))))))));
663 }
664 
TEST(DocumentSymbols,Macro)665 TEST(DocumentSymbols, Macro) {
666   struct Test {
667     const char *Code;
668     testing::Matcher<DocumentSymbol> Matcher;
669   } Tests[] = {
670       {
671           R"cpp(
672             // Basic macro that generates symbols.
673             #define DEFINE_FLAG(X) bool FLAGS_##X; bool FLAGS_no##X
674             DEFINE_FLAG(pretty);
675           )cpp",
676           AllOf(withName("DEFINE_FLAG"), withDetail("(pretty)"),
677                 children(withName("FLAGS_pretty"), withName("FLAGS_nopretty"))),
678       },
679       {
680           R"cpp(
681             // Hierarchy is determined by primary (name) location.
682             #define ID(X) X
683             namespace ID(ns) { int ID(y); }
684           )cpp",
685           AllOf(withName("ID"), withDetail("(ns)"),
686                 children(AllOf(withName("ns"),
687                                children(AllOf(withName("ID"), withDetail("(y)"),
688                                               children(withName("y"))))))),
689       },
690       {
691           R"cpp(
692             // More typical example where macro only generates part of a decl.
693             #define TEST(A, B) class A##_##B { void go(); }; void A##_##B::go()
694             TEST(DocumentSymbols, Macro) { }
695           )cpp",
696           AllOf(withName("TEST"), withDetail("(DocumentSymbols, Macro)"),
697                 children(AllOf(withName("DocumentSymbols_Macro"),
698                                children(withName("go"))),
699                          withName("DocumentSymbols_Macro::go"))),
700       },
701       {
702           R"cpp(
703             // Nested macros.
704             #define NAMESPACE(NS, BODY) namespace NS { BODY }
705             NAMESPACE(a, NAMESPACE(b, int x;))
706           )cpp",
707           AllOf(
708               withName("NAMESPACE"), withDetail("(a, NAMESPACE(b, int x;))"),
709               children(AllOf(
710                   withName("a"),
711                   children(AllOf(withName("NAMESPACE"),
712                                  // FIXME: nested expansions not in TokenBuffer
713                                  withDetail(""),
714                                  children(AllOf(withName("b"),
715                                                 children(withName("x"))))))))),
716       },
717       {
718           R"cpp(
719             // Macro invoked from body is not exposed.
720             #define INNER(X) int X
721             #define OUTER(X) INNER(X)
722             OUTER(foo);
723           )cpp",
724           AllOf(withName("OUTER"), withDetail("(foo)"),
725                 children(withName("foo"))),
726       },
727   };
728   for (const Test &T : Tests) {
729     auto TU = TestTU::withCode(T.Code);
730     EXPECT_THAT(getSymbols(TU.build()), ElementsAre(T.Matcher)) << T.Code;
731   }
732 }
733 
TEST(DocumentSymbols,RangeFromMacro)734 TEST(DocumentSymbols, RangeFromMacro) {
735   TestTU TU;
736   Annotations Main(R"(
737     #define FF(name) \
738       class name##_Test {};
739 
740     $expansion1[[FF]](abc);
741 
742     #define FF2() \
743       class Test {}
744 
745     $expansion2parens[[$expansion2[[FF2]]()]];
746 
747     #define FF3() \
748       void waldo()
749 
750     $fullDef[[FF3() {
751       int var = 42;
752     }]]
753 
754     #define FF4(name) int name = 0
755     $FooRange[[FF4($FooSelectionRange[[foo]])]];
756   )");
757   TU.Code = Main.code().str();
758   EXPECT_THAT(
759       getSymbols(TU.build()),
760       ElementsAre(
761           AllOf(withName("FF"), withDetail("(abc)"),
762                 children(AllOf(withName("abc_Test"), withDetail("class"),
763                                symNameRange(Main.range("expansion1"))))),
764           AllOf(withName("FF2"), withDetail("()"),
765                 symNameRange(Main.range("expansion2")),
766                 symRange(Main.range("expansion2parens")),
767                 children(AllOf(withName("Test"), withDetail("class"),
768                                symNameRange(Main.range("expansion2"))))),
769           AllOf(withName("FF3"), withDetail("()"),
770                 symRange(Main.range("fullDef")),
771                 children(AllOf(withName("waldo"), withDetail("void ()"),
772                                symRange(Main.range("fullDef"))))),
773           AllOf(
774               withName("FF4"), withDetail("(foo)"),
775               children(AllOf(withName("foo"), symRange(Main.range("FooRange")),
776                              symNameRange(Main.range("FooSelectionRange")))))));
777 }
778 
TEST(DocumentSymbols,FuncTemplates)779 TEST(DocumentSymbols, FuncTemplates) {
780   TestTU TU;
781   Annotations Source(R"cpp(
782     template <class T>
783     T foo() {}
784 
785     auto x = foo<int>();
786     auto y = foo<double>();
787   )cpp");
788   TU.Code = Source.code().str();
789   // Make sure we only see the template declaration, not instantiations.
790   EXPECT_THAT(getSymbols(TU.build()),
791               ElementsAre(AllOf(withName("foo"), withDetail("template T ()")),
792                           AllOf(withName("x"), withDetail("int")),
793                           AllOf(withName("y"), withDetail("double"))));
794 }
795 
TEST(DocumentSymbols,UsingDirectives)796 TEST(DocumentSymbols, UsingDirectives) {
797   TestTU TU;
798   Annotations Source(R"cpp(
799     namespace ns {
800       int foo;
801     }
802 
803     namespace ns_alias = ns;
804 
805     using namespace ::ns;     // check we don't loose qualifiers.
806     using namespace ns_alias; // and namespace aliases.
807   )cpp");
808   TU.Code = Source.code().str();
809   EXPECT_THAT(getSymbols(TU.build()),
810               ElementsAre(withName("ns"), withName("ns_alias"),
811                           withName("using namespace ::ns"),
812                           withName("using namespace ns_alias")));
813 }
814 
TEST(DocumentSymbols,TempSpecs)815 TEST(DocumentSymbols, TempSpecs) {
816   TestTU TU;
817   TU.Code = R"cpp(
818       template <typename T, typename U, int X = 5> class Foo {};
819       template <typename T> class Foo<int, T> {};
820       template <> class Foo<bool, int> {};
821       template <> class Foo<bool, int, 3> {};
822       )cpp";
823   // Foo is higher ranked because of exact name match.
824   EXPECT_THAT(getSymbols(TU.build()),
825               UnorderedElementsAre(
826                   AllOf(withName("Foo"), withKind(SymbolKind::Class),
827                         withDetail("template class")),
828                   AllOf(withName("Foo<int, T>"), withKind(SymbolKind::Class),
829                         withDetail("template class")),
830                   AllOf(withName("Foo<bool, int>"), withKind(SymbolKind::Class),
831                         withDetail("class")),
832                   AllOf(withName("Foo<bool, int, 3>"),
833                         withKind(SymbolKind::Class), withDetail("class"))));
834 }
835 
TEST(DocumentSymbols,Qualifiers)836 TEST(DocumentSymbols, Qualifiers) {
837   TestTU TU;
838   TU.Code = R"cpp(
839     namespace foo { namespace bar {
840       struct Cls;
841 
842       int func1();
843       int func2();
844       int func3();
845       int func4();
846     }}
847 
848     struct foo::bar::Cls { };
849 
850     int foo::bar::func1() { return 10; }
851     int ::foo::bar::func2() { return 20; }
852 
853     using namespace foo;
854     int bar::func3() { return 30; }
855 
856     namespace alias = foo::bar;
857     int ::alias::func4() { return 40; }
858   )cpp";
859 
860   // All the qualifiers should be preserved exactly as written.
861   EXPECT_THAT(getSymbols(TU.build()),
862               UnorderedElementsAre(
863                   withName("foo"), withName("foo::bar::Cls"),
864                   withName("foo::bar::func1"), withName("::foo::bar::func2"),
865                   withName("using namespace foo"), withName("bar::func3"),
866                   withName("alias"), withName("::alias::func4")));
867 }
868 
TEST(DocumentSymbols,QualifiersWithTemplateArgs)869 TEST(DocumentSymbols, QualifiersWithTemplateArgs) {
870   TestTU TU;
871   TU.Code = R"cpp(
872       template <typename T, typename U = double> class Foo;
873 
874       template <>
875       class Foo<int, double> {
876         int method1();
877         int method2();
878         int method3();
879       };
880 
881       using int_type = int;
882 
883       // Typedefs should be preserved!
884       int Foo<int_type, double>::method1() { return 10; }
885 
886       // Default arguments should not be shown!
887       int Foo<int>::method2() { return 20; }
888 
889       using Foo_type = Foo<int>;
890       // If the whole type is aliased, this should be preserved too!
891       int Foo_type::method3() { return 30; }
892       )cpp";
893   EXPECT_THAT(getSymbols(TU.build()),
894               UnorderedElementsAre(
895                   AllOf(withName("Foo"), withDetail("template class")),
896                   AllOf(withName("Foo<int, double>"), withDetail("class")),
897                   AllOf(withName("int_type"), withDetail("type alias")),
898                   AllOf(withName("Foo<int_type, double>::method1"),
899                         withDetail("int ()")),
900                   AllOf(withName("Foo<int>::method2"), withDetail("int ()")),
901                   AllOf(withName("Foo_type"), withDetail("type alias")),
902                   AllOf(withName("Foo_type::method3"), withDetail("int ()"))));
903 }
904 
TEST(DocumentSymbolsTest,Ranges)905 TEST(DocumentSymbolsTest, Ranges) {
906   TestTU TU;
907   Annotations Main(R"(
908       $foo[[int foo(bool Argument) {
909         return 42;
910       }]]
911 
912       $variable[[char GLOBAL_VARIABLE]];
913 
914       $ns[[namespace ns {
915       $bar[[class Bar {
916       public:
917         $ctor[[Bar() {}]]
918         $dtor[[~Bar()]];
919 
920       private:
921         $field[[unsigned Baz]];
922 
923         $getbaz[[unsigned getBaz() { return Baz; }]]
924       }]];
925       }]] // namespace ns
926 
927       $forwardclass[[class ForwardClassDecl]];
928 
929       $struct[[struct StructDefinition {
930         $structfield[[int *Pointer = nullptr]];
931       }]];
932       $forwardstruct[[struct StructDeclaration]];
933 
934       $forwardfunc[[void forwardFunctionDecl(int Something)]];
935     )");
936   TU.Code = Main.code().str();
937   EXPECT_THAT(
938       getSymbols(TU.build()),
939       UnorderedElementsAre(
940           AllOf(withName("foo"), withKind(SymbolKind::Function),
941                 withDetail("int (bool)"), symRange(Main.range("foo"))),
942           AllOf(withName("GLOBAL_VARIABLE"), withKind(SymbolKind::Variable),
943                 withDetail("char"), symRange(Main.range("variable"))),
944           AllOf(
945               withName("ns"), withKind(SymbolKind::Namespace),
946               symRange(Main.range("ns")),
947               children(AllOf(
948                   withName("Bar"), withKind(SymbolKind::Class),
949                   withDetail("class"), symRange(Main.range("bar")),
950                   children(
951                       AllOf(withName("Bar"), withKind(SymbolKind::Constructor),
952                             withDetail("()"), symRange(Main.range("ctor"))),
953                       AllOf(withName("~Bar"), withKind(SymbolKind::Constructor),
954                             withDetail(""), symRange(Main.range("dtor"))),
955                       AllOf(withName("Baz"), withKind(SymbolKind::Field),
956                             withDetail("unsigned int"),
957                             symRange(Main.range("field"))),
958                       AllOf(withName("getBaz"), withKind(SymbolKind::Method),
959                             withDetail("unsigned int ()"),
960                             symRange(Main.range("getbaz"))))))),
961           AllOf(withName("ForwardClassDecl"), withKind(SymbolKind::Class),
962                 withDetail("class"), symRange(Main.range("forwardclass"))),
963           AllOf(withName("StructDefinition"), withKind(SymbolKind::Struct),
964                 withDetail("struct"), symRange(Main.range("struct")),
965                 children(AllOf(withName("Pointer"), withKind(SymbolKind::Field),
966                                withDetail("int *"),
967                                symRange(Main.range("structfield"))))),
968           AllOf(withName("StructDeclaration"), withKind(SymbolKind::Struct),
969                 withDetail("struct"), symRange(Main.range("forwardstruct"))),
970           AllOf(withName("forwardFunctionDecl"), withKind(SymbolKind::Function),
971                 withDetail("void (int)"),
972                 symRange(Main.range("forwardfunc")))));
973 }
974 
TEST(DocumentSymbolsTest,DependentType)975 TEST(DocumentSymbolsTest, DependentType) {
976   TestTU TU;
977   TU.Code = R"(
978     template <typename T> auto plus(T x, T y) -> decltype(x + y) { return x + y; }
979 
980     template <typename Key, typename Value> class Pair {};
981 
982     template <typename Key, typename Value>
983     struct Context : public Pair<Key, Value> {
984       using Pair<Key, Value>::Pair;
985     };
986     )";
987   EXPECT_THAT(
988       getSymbols(TU.build()),
989       ElementsAre(
990           AllOf(withName("plus"),
991                 withDetail("template auto (T, T) -> decltype(x + y)")),
992           AllOf(withName("Pair"), withDetail("template class")),
993           AllOf(withName("Context"), withDetail("template struct"),
994                 children(AllOf(
995                     withName("Pair<type-parameter-0-0, type-parameter-0-1>"),
996                     withDetail("<dependent type>"))))));
997 }
998 
TEST(DocumentSymbolsTest,ObjCCategoriesAndClassExtensions)999 TEST(DocumentSymbolsTest, ObjCCategoriesAndClassExtensions) {
1000   TestTU TU;
1001   TU.ExtraArgs = {"-xobjective-c++", "-Wno-objc-root-class"};
1002   Annotations Main(R"cpp(
1003       $Cat[[@interface Cat
1004       + (id)sharedCat;
1005       @end]]
1006       $SneakyCat[[@interface Cat (Sneaky)
1007       - (id)sneak:(id)behavior;
1008       @end]]
1009 
1010       $MeowCat[[@interface Cat ()
1011       - (void)meow;
1012       @end]]
1013       $PurCat[[@interface Cat ()
1014       - (void)pur;
1015       @end]]
1016     )cpp");
1017   TU.Code = Main.code().str();
1018   EXPECT_THAT(
1019       getSymbols(TU.build()),
1020       ElementsAre(
1021           AllOf(withName("Cat"), symRange(Main.range("Cat")),
1022                 children(AllOf(withName("+sharedCat"),
1023                                withKind(SymbolKind::Method)))),
1024           AllOf(withName("Cat(Sneaky)"), symRange(Main.range("SneakyCat")),
1025                 children(
1026                     AllOf(withName("-sneak:"), withKind(SymbolKind::Method)))),
1027           AllOf(
1028               withName("Cat()"), symRange(Main.range("MeowCat")),
1029               children(AllOf(withName("-meow"), withKind(SymbolKind::Method)))),
1030           AllOf(withName("Cat()"), symRange(Main.range("PurCat")),
1031                 children(
1032                     AllOf(withName("-pur"), withKind(SymbolKind::Method))))));
1033 }
1034 
TEST(DocumentSymbolsTest,PragmaMarkGroups)1035 TEST(DocumentSymbolsTest, PragmaMarkGroups) {
1036   TestTU TU;
1037   TU.ExtraArgs = {"-xobjective-c++", "-Wno-objc-root-class"};
1038   Annotations Main(R"cpp(
1039       $DogDef[[@interface Dog
1040       @end]]
1041 
1042       $DogImpl[[@implementation Dog
1043 
1044       + (id)sharedDoggo { return 0; }
1045 
1046       #pragma $Overrides[[mark - Overrides
1047 
1048       - (id)init {
1049         return self;
1050       }
1051       - (void)bark {}]]
1052 
1053       #pragma $Specifics[[mark - Dog Specifics
1054 
1055       - (int)isAGoodBoy {
1056         return 1;
1057       }]]
1058       @]]end  // FIXME: Why doesn't this include the 'end'?
1059 
1060       #pragma $End[[mark - End
1061 ]]
1062     )cpp");
1063   TU.Code = Main.code().str();
1064   EXPECT_THAT(
1065       getSymbols(TU.build()),
1066       UnorderedElementsAre(
1067           AllOf(withName("Dog"), symRange(Main.range("DogDef"))),
1068           AllOf(withName("Dog"), symRange(Main.range("DogImpl")),
1069                 children(AllOf(withName("+sharedDoggo"),
1070                                withKind(SymbolKind::Method)),
1071                          AllOf(withName("Overrides"),
1072                                symRange(Main.range("Overrides")),
1073                                children(AllOf(withName("-init"),
1074                                               withKind(SymbolKind::Method)),
1075                                         AllOf(withName("-bark"),
1076                                               withKind(SymbolKind::Method)))),
1077                          AllOf(withName("Dog Specifics"),
1078                                symRange(Main.range("Specifics")),
1079                                children(AllOf(withName("-isAGoodBoy"),
1080                                               withKind(SymbolKind::Method)))))),
1081           AllOf(withName("End"), symRange(Main.range("End")))));
1082 }
1083 
TEST(DocumentSymbolsTest,PragmaMarkGroupsNesting)1084 TEST(DocumentSymbolsTest, PragmaMarkGroupsNesting) {
1085   TestTU TU;
1086   TU.ExtraArgs = {"-xobjective-c++", "-Wno-objc-root-class"};
1087   Annotations Main(R"cpp(
1088       #pragma mark - Foo
1089       struct Foo {
1090         #pragma mark - Bar
1091         void bar() {
1092            #pragma mark - NotTopDecl
1093         }
1094       };
1095       void bar() {}
1096     )cpp");
1097   TU.Code = Main.code().str();
1098   EXPECT_THAT(
1099       getSymbols(TU.build()),
1100       UnorderedElementsAre(AllOf(
1101           withName("Foo"),
1102           children(AllOf(withName("Foo"),
1103                          children(AllOf(withName("Bar"),
1104                                         children(AllOf(withName("bar"),
1105                                                        children(withName(
1106                                                            "NotTopDecl"))))))),
1107                    withName("bar")))));
1108 }
1109 
TEST(DocumentSymbolsTest,PragmaMarkGroupsNoNesting)1110 TEST(DocumentSymbolsTest, PragmaMarkGroupsNoNesting) {
1111   TestTU TU;
1112   TU.ExtraArgs = {"-xobjective-c++", "-Wno-objc-root-class"};
1113   Annotations Main(R"cpp(
1114       #pragma mark Helpers
1115       void helpA(id obj) {}
1116 
1117       #pragma mark -
1118       #pragma mark Core
1119 
1120       void coreMethod() {}
1121     )cpp");
1122   TU.Code = Main.code().str();
1123   EXPECT_THAT(getSymbols(TU.build()),
1124               UnorderedElementsAre(withName("Helpers"), withName("helpA"),
1125                                    withName("(unnamed group)"),
1126                                    withName("Core"), withName("coreMethod")));
1127 }
1128 
1129 } // namespace
1130 } // namespace clangd
1131 } // namespace clang
1132