clang-tools 10.0.0

FindSymbolsTests.cpp
Go to the documentation of this file.
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 "ClangdServer.h"
10 #include "FindSymbols.h"
11 #include "SyncAPI.h"
12 #include "TestFS.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 class IgnoreDiagnostics : public DiagnosticsConsumer {
29 void onDiagnosticsReady(PathRef File,
30 std::vector<Diag> Diagnostics) override {}
31 };
32
33 // GMock helpers for matching SymbolInfos items.
34 MATCHER_P(QName, Name, "") {
35 if (arg.containerName.empty())
36 return arg.name == Name;
37 return (arg.containerName + "::" + arg.name) == Name;
38 }
39 MATCHER_P(WithName, N, "") { return arg.name == N; }
40 MATCHER_P(WithKind, Kind, "") { return arg.kind == Kind; }
41 MATCHER_P(SymRange, Range, "") { return arg.location.range == Range; }
42
43 // GMock helpers for matching DocumentSymbol.
44 MATCHER_P(SymNameRange, Range, "") { return arg.selectionRange == Range; }
45 template <class... ChildMatchers>
46 ::testing::Matcher<DocumentSymbol> Children(ChildMatchers... ChildrenM) {
47 return Field(&DocumentSymbol::children, ElementsAre(ChildrenM...));
48 }
49
50 ClangdServer::Options optsForTests() {
51 auto ServerOpts = ClangdServer::optsForTest();
52 ServerOpts.WorkspaceRoot = testRoot();
53 ServerOpts.BuildDynamicSymbolIndex = true;
54 return ServerOpts;
55 }
56
57 class WorkspaceSymbolsTest : public ::testing::Test {
58 public:
59 WorkspaceSymbolsTest()
60 : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {
61 // Make sure the test root directory is created.
62 FSProvider.Files[testPath("unused")] = "";
63 CDB.ExtraClangFlags = {"-xc++"};
64 }
65
66 protected:
67 MockFSProvider FSProvider;
68 MockCompilationDatabase CDB;
69 IgnoreDiagnostics DiagConsumer;
70 ClangdServer Server;
71 int Limit = 0;
72
73 std::vector<SymbolInformation> getSymbols(llvm::StringRef Query) {
74 EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
75 auto SymbolInfos = runWorkspaceSymbols(Server, Query, Limit);
76 EXPECT_TRUE(bool(SymbolInfos)) << "workspaceSymbols returned an error";
77 return *SymbolInfos;
78 }
79
80 void addFile(llvm::StringRef FileName, llvm::StringRef Contents) {
81 auto Path = testPath(FileName);
82 FSProvider.Files[Path] = Contents;
83 Server.addDocument(Path, Contents);
84 }
85 };
86
87 } // namespace
88
89 TEST_F(WorkspaceSymbolsTest, Macros) {
90 addFile("foo.cpp", R"cpp(
91 #define MACRO X
92 )cpp");
93
94 // LSP's SymbolKind doesn't have a "Macro" kind, and
95 // indexSymbolKindToSymbolKind() currently maps macros
96 // to SymbolKind::String.
97 EXPECT_THAT(getSymbols("macro"),
98 ElementsAre(AllOf(QName("MACRO"), WithKind(SymbolKind::String))));
99 }
100
101 TEST_F(WorkspaceSymbolsTest, NoLocals) {
102 addFile("foo.cpp", R"cpp(
103 void test(int FirstParam, int SecondParam) {
104 struct LocalClass {};
105 int local_var;
106 })cpp");
107 EXPECT_THAT(getSymbols("l"), IsEmpty());
108 EXPECT_THAT(getSymbols("p"), IsEmpty());
109 }
110
111 TEST_F(WorkspaceSymbolsTest, Globals) {
112 addFile("foo.h", R"cpp(
113 int global_var;
114
115 int global_func();
116
117 struct GlobalStruct {};)cpp");
118 addFile("foo.cpp", R"cpp(
119 #include "foo.h"
120 )cpp");
121 EXPECT_THAT(getSymbols("global"),
122 UnorderedElementsAre(
123 AllOf(QName("GlobalStruct"), WithKind(SymbolKind::Struct)),
124 AllOf(QName("global_func"), WithKind(SymbolKind::Function)),
125 AllOf(QName("global_var"), WithKind(SymbolKind::Variable))));
126 }
127
128 TEST_F(WorkspaceSymbolsTest, Unnamed) {
129 addFile("foo.h", R"cpp(
130 struct {
131 int InUnnamed;
132 } UnnamedStruct;)cpp");
133 addFile("foo.cpp", R"cpp(
134 #include "foo.h"
135 )cpp");
136 EXPECT_THAT(getSymbols("UnnamedStruct"),
137 ElementsAre(AllOf(QName("UnnamedStruct"),
138 WithKind(SymbolKind::Variable))));
139 EXPECT_THAT(getSymbols("InUnnamed"),
140 ElementsAre(AllOf(QName("(anonymous struct)::InUnnamed"),
141 WithKind(SymbolKind::Field))));
142 }
143
144 TEST_F(WorkspaceSymbolsTest, InMainFile) {
145 addFile("foo.cpp", R"cpp(
146 int test() {}
147 static test2() {}
148 )cpp");
149 EXPECT_THAT(getSymbols("test"), ElementsAre(QName("test"), QName("test2")));
150 }
151
152 TEST_F(WorkspaceSymbolsTest, Namespaces) {
153 addFile("foo.h", R"cpp(
154 namespace ans1 {
155 int ai1;
156 namespace ans2 {
157 int ai2;
158 }
159 }
160 )cpp");
161 addFile("foo.cpp", R"cpp(
162 #include "foo.h"
163 )cpp");
164 EXPECT_THAT(getSymbols("a"),
165 UnorderedElementsAre(QName("ans1"), QName("ans1::ai1"),
166 QName("ans1::ans2"),
167 QName("ans1::ans2::ai2")));
168 EXPECT_THAT(getSymbols("::"), ElementsAre(QName("ans1")));
169 EXPECT_THAT(getSymbols("::a"), ElementsAre(QName("ans1")));
170 EXPECT_THAT(getSymbols("ans1::"),
171 UnorderedElementsAre(QName("ans1::ai1"), QName("ans1::ans2")));
172 EXPECT_THAT(getSymbols("::ans1"), ElementsAre(QName("ans1")));
173 EXPECT_THAT(getSymbols("::ans1::"),
174 UnorderedElementsAre(QName("ans1::ai1"), QName("ans1::ans2")));
175 EXPECT_THAT(getSymbols("::ans1::ans2"), ElementsAre(QName("ans1::ans2")));
176 EXPECT_THAT(getSymbols("::ans1::ans2::"),
177 ElementsAre(QName("ans1::ans2::ai2")));
178 }
179
180 TEST_F(WorkspaceSymbolsTest, AnonymousNamespace) {
181 addFile("foo.cpp", R"cpp(
182 namespace {
183 void test() {}
184 }
185 )cpp");
186 EXPECT_THAT(getSymbols("test"), ElementsAre(QName("test")));
187 }
188
189 TEST_F(WorkspaceSymbolsTest, MultiFile) {
190 addFile("foo.h", R"cpp(
191 int foo() {
192 }
193 )cpp");
194 addFile("foo2.h", R"cpp(
195 int foo2() {
196 }
197 )cpp");
198 addFile("foo.cpp", R"cpp(
199 #include "foo.h"
200 #include "foo2.h"
201 )cpp");
202 EXPECT_THAT(getSymbols("foo"),
203 UnorderedElementsAre(QName("foo"), QName("foo2")));
204 }
205
206 TEST_F(WorkspaceSymbolsTest, GlobalNamespaceQueries) {
207 addFile("foo.h", R"cpp(
208 int foo() {
209 }
210 class Foo {
211 int a;
212 };
213 namespace ns {
214 int foo2() {
215 }
216 }
217 )cpp");
218 addFile("foo.cpp", R"cpp(
219 #include "foo.h"
220 )cpp");
221 EXPECT_THAT(getSymbols("::"),
222 UnorderedElementsAre(
223 AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
224 AllOf(QName("foo"), WithKind(SymbolKind::Function)),
225 AllOf(QName("ns"), WithKind(SymbolKind::Namespace))));
226 EXPECT_THAT(getSymbols(":"), IsEmpty());
227 EXPECT_THAT(getSymbols(""), IsEmpty());
228 }
229
230 TEST_F(WorkspaceSymbolsTest, Enums) {
231 addFile("foo.h", R"cpp(
232 enum {
233 Red
234 };
235 enum Color {
236 Green
237 };
238 enum class Color2 {
239 Yellow
240 };
241 namespace ns {
242 enum {
243 Black
244 };
245 enum Color3 {
246 Blue
247 };
248 enum class Color4 {
249 White
250 };
251 }
252 )cpp");
253 addFile("foo.cpp", R"cpp(
254 #include "foo.h"
255 )cpp");
256 EXPECT_THAT(getSymbols("Red"), ElementsAre(QName("Red")));
257 EXPECT_THAT(getSymbols("::Red"), ElementsAre(QName("Red")));
258 EXPECT_THAT(getSymbols("Green"), ElementsAre(QName("Green")));
259 EXPECT_THAT(getSymbols("Green"), ElementsAre(QName("Green")));
260 EXPECT_THAT(getSymbols("Color2::Yellow"),
261 ElementsAre(QName("Color2::Yellow")));
262 EXPECT_THAT(getSymbols("Yellow"), ElementsAre(QName("Color2::Yellow")));
263
264 EXPECT_THAT(getSymbols("ns::Black"), ElementsAre(QName("ns::Black")));
265 EXPECT_THAT(getSymbols("ns::Blue"), ElementsAre(QName("ns::Blue")));
266 EXPECT_THAT(getSymbols("ns::Color4::White"),
267 ElementsAre(QName("ns::Color4::White")));
268 }
269
270 TEST_F(WorkspaceSymbolsTest, Ranking) {
271 addFile("foo.h", R"cpp(
272 namespace ns{}
273 void func();
274 )cpp");
275 addFile("foo.cpp", R"cpp(
276 #include "foo.h"
277 )cpp");
278 EXPECT_THAT(getSymbols("::"), ElementsAre(QName("func"), QName("ns")));
279 }
280
281 TEST_F(WorkspaceSymbolsTest, WithLimit) {
282 addFile("foo.h", R"cpp(
283 int foo;
284 int foo2;
285 )cpp");
286 addFile("foo.cpp", R"cpp(
287 #include "foo.h"
288 )cpp");
289 // Foo is higher ranked because of exact name match.
290 EXPECT_THAT(getSymbols("foo"),
291 UnorderedElementsAre(
292 AllOf(QName("foo"), WithKind(SymbolKind::Variable)),
293 AllOf(QName("foo2"), WithKind(SymbolKind::Variable))));
294
295 Limit = 1;
296 EXPECT_THAT(getSymbols("foo"), ElementsAre(QName("foo")));
297 }
298
299 TEST_F(WorkspaceSymbolsTest, TempSpecs) {
300 addFile("foo.h", R"cpp(
301 template <typename T, typename U, int X = 5> class Foo {};
302 template <typename T> class Foo<int, T> {};
303 template <> class Foo<bool, int> {};
304 template <> class Foo<bool, int, 3> {};
305 )cpp");
306 // Foo is higher ranked because of exact name match.
307 EXPECT_THAT(
308 getSymbols("Foo"),
309 UnorderedElementsAre(
310 AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
311 AllOf(QName("Foo<int, T>"), WithKind(SymbolKind::Class)),
312 AllOf(QName("Foo<bool, int>"), WithKind(SymbolKind::Class)),
313 AllOf(QName("Foo<bool, int, 3>"), WithKind(SymbolKind::Class))));
314 }
315
316 namespace {
317 class DocumentSymbolsTest : public ::testing::Test {
318 public:
319 DocumentSymbolsTest()
320 : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {}
321
322 protected:
323 MockFSProvider FSProvider;
324 MockCompilationDatabase CDB;
325 IgnoreDiagnostics DiagConsumer;
326 ClangdServer Server;
327
328 std::vector<DocumentSymbol> getSymbols(PathRef File) {
329 EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
330 auto SymbolInfos = runDocumentSymbols(Server, File);
331 EXPECT_TRUE(bool(SymbolInfos)) << "documentSymbols returned an error";
332 return *SymbolInfos;
333 }
334
335 void addFile(llvm::StringRef FilePath, llvm::StringRef Contents) {
336 FSProvider.Files[FilePath] = Contents;
337 Server.addDocument(FilePath, Contents);
338 }
339 };
340 } // namespace
341
342 TEST_F(DocumentSymbolsTest, BasicSymbols) {
343 std::string FilePath = testPath("foo.cpp");
344 Annotations Main(R"(
345 class Foo;
346 class Foo {
347 Foo() {}
348 Foo(int a) {}
349 void $decl[[f]]();
350 friend void f1();
351 friend class Friend;
352 Foo& operator=(const Foo&);
353 ~Foo();
354 class Nested {
355 void f();
356 };
357 };
358 class Friend {
359 };
360
361 void f1();
362 inline void f2() {}
363 static const int KInt = 2;
364 const char* kStr = "123";
365
366 void f1() {}
367
368 namespace foo {
369 // Type alias
370 typedef int int32;
371 using int32_t = int32;
372
373 // Variable
374 int v1;
375
376 // Namespace
377 namespace bar {
378 int v2;
379 }
380 // Namespace alias
381 namespace baz = bar;
382
383 using bar::v2;
384 } // namespace foo
385 )");
386
387 addFile(FilePath, Main.code());
388 EXPECT_THAT(
389 getSymbols(FilePath),
390 ElementsAreArray(
391 {AllOf(WithName("Foo"), WithKind(SymbolKind::Class), Children()),
392 AllOf(WithName("Foo"), WithKind(SymbolKind::Class),
393 Children(AllOf(WithName("Foo"),
394 WithKind(SymbolKind::Constructor), Children()),
395 AllOf(WithName("Foo"),
396 WithKind(SymbolKind::Constructor), Children()),
397 AllOf(WithName("f"), WithKind(SymbolKind::Method),
398 Children()),
399 AllOf(WithName("operator="),
400 WithKind(SymbolKind::Method), Children()),
401 AllOf(WithName("~Foo"),
402 WithKind(SymbolKind::Constructor), Children()),
403 AllOf(WithName("Nested"), WithKind(SymbolKind::Class),
404 Children(AllOf(WithName("f"),
405 WithKind(SymbolKind::Method),
406 Children()))))),
407 AllOf(WithName("Friend"), WithKind(SymbolKind::Class), Children()),
408 AllOf(WithName("f1"), WithKind(SymbolKind::Function), Children()),
409 AllOf(WithName("f2"), WithKind(SymbolKind::Function), Children()),
410 AllOf(WithName("KInt"), WithKind(SymbolKind::Variable), Children()),
411 AllOf(WithName("kStr"), WithKind(SymbolKind::Variable), Children()),
412 AllOf(WithName("f1"), WithKind(SymbolKind::Function), Children()),
413 AllOf(
414 WithName("foo"), WithKind(SymbolKind::Namespace),
415 Children(
416 AllOf(WithName("int32"), WithKind(SymbolKind::Class),
417 Children()),
418 AllOf(WithName("int32_t"), WithKind(SymbolKind::Class),
419 Children()),
420 AllOf(WithName("v1"), WithKind(SymbolKind::Variable),
421 Children()),
422 AllOf(WithName("bar"), WithKind(SymbolKind::Namespace),
423 Children(AllOf(WithName("v2"),
424 WithKind(SymbolKind::Variable),
425 Children()))),
426 AllOf(WithName("baz"), WithKind(SymbolKind::Namespace),
427 Children()),
428 AllOf(WithName("v2"), WithKind(SymbolKind::Namespace))))}));
429 }
430
431 TEST_F(DocumentSymbolsTest, DeclarationDefinition) {
432 std::string FilePath = testPath("foo.cpp");
433 Annotations Main(R"(
434 class Foo {
435 void $decl[[f]]();
436 };
437 void Foo::$def[[f]]() {
438 }
439 )");
440
441 addFile(FilePath, Main.code());
442 EXPECT_THAT(
443 getSymbols(FilePath),
444 ElementsAre(
445 AllOf(WithName("Foo"), WithKind(SymbolKind::Class),
446 Children(AllOf(WithName("f"), WithKind(SymbolKind::Method),
447 SymNameRange(Main.range("decl"))))),
448 AllOf(WithName("Foo::f"), WithKind(SymbolKind::Method),
449 SymNameRange(Main.range("def")))));
450 }
451
452 TEST_F(DocumentSymbolsTest, ExternSymbol) {
453 std::string FilePath = testPath("foo.cpp");
454 addFile(testPath("foo.h"), R"cpp(
455 extern int var;
456 )cpp");
457 addFile(FilePath, R"cpp(
458 #include "foo.h"
459 )cpp");
460
461 EXPECT_THAT(getSymbols(FilePath), IsEmpty());
462 }
463
464 TEST_F(DocumentSymbolsTest, NoLocals) {
465 std::string FilePath = testPath("foo.cpp");
466 addFile(FilePath,
467 R"cpp(
468 void test(int FirstParam, int SecondParam) {
469 struct LocalClass {};
470 int local_var;
471 })cpp");
472 EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test")));
473 }
474
475 TEST_F(DocumentSymbolsTest, Unnamed) {
476 std::string FilePath = testPath("foo.h");
477 addFile(FilePath,
478 R"cpp(
479 struct {
480 int InUnnamed;
481 } UnnamedStruct;
482 )cpp");
483 EXPECT_THAT(
484 getSymbols(FilePath),
485 ElementsAre(
486 AllOf(WithName("(anonymous struct)"), WithKind(SymbolKind::Struct),
487 Children(AllOf(WithName("InUnnamed"),
488 WithKind(SymbolKind::Field), Children()))),
489 AllOf(WithName("UnnamedStruct"), WithKind(SymbolKind::Variable),
490 Children())));
491 }
492
493 TEST_F(DocumentSymbolsTest, InHeaderFile) {
494 addFile(testPath("bar.h"), R"cpp(
495 int foo() {
496 }
497 )cpp");
498 std::string FilePath = testPath("foo.h");
499 addFile(FilePath, R"cpp(
500 #include "bar.h"
501 int test() {
502 }
503 )cpp");
504 addFile(testPath("foo.cpp"), R"cpp(
505 #include "foo.h"
506 )cpp");
507 EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test")));
508 }
509
510 TEST_F(DocumentSymbolsTest, Template) {
511 std::string FilePath = testPath("foo.cpp");
512 addFile(FilePath, R"(
513 template <class T> struct Tmpl {T x = 0;};
514 template <> struct Tmpl<int> {
515 int y = 0;
516 };
517 extern template struct Tmpl<float>;
518 template struct Tmpl<double>;
519
520 template <class T, class U, class Z = float>
521 int funcTmpl(U a);
522 template <>
523 int funcTmpl<int>(double a);
524
525 template <class T, class U = double>
526 int varTmpl = T();
527 template <>
528 double varTmpl<int> = 10.0;
529 )");
530 EXPECT_THAT(
531 getSymbols(FilePath),
532 ElementsAre(
533 AllOf(WithName("Tmpl"), WithKind(SymbolKind::Struct),
534 Children(AllOf(WithName("x"), WithKind(SymbolKind::Field)))),
535 AllOf(WithName("Tmpl<int>"), WithKind(SymbolKind::Struct),
536 Children(WithName("y"))),
537 AllOf(WithName("Tmpl<float>"), WithKind(SymbolKind::Struct),
538 Children()),
539 AllOf(WithName("Tmpl<double>"), WithKind(SymbolKind::Struct),
540 Children()),
541 AllOf(WithName("funcTmpl"), Children()),
542 AllOf(WithName("funcTmpl<int>"), Children()),
543 AllOf(WithName("varTmpl"), Children()),
544 AllOf(WithName("varTmpl<int>"), Children())));
545 }
546
547 TEST_F(DocumentSymbolsTest, Namespaces) {
548 std::string FilePath = testPath("foo.cpp");
549 addFile(FilePath, R"cpp(
550 namespace ans1 {
551 int ai1;
552 namespace ans2 {
553 int ai2;
554 }
555 }
556 namespace {
557 void test() {}
558 }
559
560 namespace na {
561 inline namespace nb {
562 class Foo {};
563 }
564 }
565 namespace na {
566 // This is still inlined.
567 namespace nb {
568 class Bar {};
569 }
570 }
571 )cpp");
572 EXPECT_THAT(
573 getSymbols(FilePath),
574 ElementsAreArray<::testing::Matcher<DocumentSymbol>>(
575 {AllOf(WithName("ans1"),
576 Children(AllOf(WithName("ai1"), Children()),
577 AllOf(WithName("ans2"), Children(WithName("ai2"))))),
578 AllOf(WithName("(anonymous namespace)"), Children(WithName("test"))),
579 AllOf(WithName("na"),
580 Children(AllOf(WithName("nb"), Children(WithName("Foo"))))),
581 AllOf(WithName("na"),
582 Children(AllOf(WithName("nb"), Children(WithName("Bar")))))}));
583 }
584
585 TEST_F(DocumentSymbolsTest, Enums) {
586 std::string FilePath = testPath("foo.cpp");
587 addFile(FilePath, R"(
588 enum {
589 Red
590 };
591 enum Color {
592 Green
593 };
594 enum class Color2 {
595 Yellow
596 };
597 namespace ns {
598 enum {
599 Black
600 };
601 }
602 )");
603 EXPECT_THAT(
604 getSymbols(FilePath),
605 ElementsAre(
606 AllOf(WithName("(anonymous enum)"), Children(WithName("Red"))),
607 AllOf(WithName("Color"), Children(WithName("Green"))),
608 AllOf(WithName("Color2"), Children(WithName("Yellow"))),
609 AllOf(WithName("ns"), Children(AllOf(WithName("(anonymous enum)"),
610 Children(WithName("Black")))))));
611 }
612
613 TEST_F(DocumentSymbolsTest, FromMacro) {
614 std::string FilePath = testPath("foo.cpp");
615 Annotations Main(R"(
616 #define FF(name) \
617 class name##_Test {};
618
619 $expansion[[FF]](abc);
620
621 #define FF2() \
622 class $spelling[[Test]] {};
623
624 FF2();
625 )");
626 addFile(FilePath, Main.code());
627 EXPECT_THAT(
628 getSymbols(FilePath),
629 ElementsAre(
630 AllOf(WithName("abc_Test"), SymNameRange(Main.range("expansion"))),
631 AllOf(WithName("Test"), SymNameRange(Main.range("spelling")))));
632 }
633
634 TEST_F(DocumentSymbolsTest, FuncTemplates) {
635 std::string FilePath = testPath("foo.cpp");
636 Annotations Source(R"cpp(
637 template <class T>
638 T foo() {}
639
640 auto x = foo<int>();
641 auto y = foo<double>()
642 )cpp");
643 addFile(FilePath, Source.code());
644 // Make sure we only see the template declaration, not instantiations.
645 EXPECT_THAT(getSymbols(FilePath),
646 ElementsAre(WithName("foo"), WithName("x"), WithName("y")));
647 }
648
649 TEST_F(DocumentSymbolsTest, UsingDirectives) {
650 std::string FilePath = testPath("foo.cpp");
651 Annotations Source(R"cpp(
652 namespace ns {
653 int foo;
654 }
655
656 namespace ns_alias = ns;
657
658 using namespace ::ns; // check we don't loose qualifiers.
659 using namespace ns_alias; // and namespace aliases.
660 )cpp");
661 addFile(FilePath, Source.code());
662 EXPECT_THAT(getSymbols(FilePath),
663 ElementsAre(WithName("ns"), WithName("ns_alias"),
664 WithName("using namespace ::ns"),
665 WithName("using namespace ns_alias")));
666 }
667
668 TEST_F(DocumentSymbolsTest, TempSpecs) {
669 addFile("foo.cpp", R"cpp(
670 template <typename T, typename U, int X = 5> class Foo {};
671 template <typename T> class Foo<int, T> {};
672 template <> class Foo<bool, int> {};
673 template <> class Foo<bool, int, 3> {};
674 )cpp");
675 // Foo is higher ranked because of exact name match.
676 EXPECT_THAT(
677 getSymbols("foo.cpp"),
678 UnorderedElementsAre(
679 AllOf(WithName("Foo"), WithKind(SymbolKind::Class)),
680 AllOf(WithName("Foo<int, T>"), WithKind(SymbolKind::Class)),
681 AllOf(WithName("Foo<bool, int>"), WithKind(SymbolKind::Class)),
682 AllOf(WithName("Foo<bool, int, 3>"), WithKind(SymbolKind::Class))));
683 }
684
685 TEST_F(DocumentSymbolsTest, Qualifiers) {
686 addFile("foo.cpp", R"cpp(
687 namespace foo { namespace bar {
688 struct Cls;
689
690 int func1();
691 int func2();
692 int func3();
693 int func4();
694 }}
695
696 struct foo::bar::Cls { };
697
698 int foo::bar::func1() { return 10; }
699 int ::foo::bar::func2() { return 20; }
700
701 using namespace foo;
702 int bar::func3() { return 30; }
703
704 namespace alias = foo::bar;
705 int ::alias::func4() { return 40; }
706 )cpp");
707
708 // All the qualifiers should be preserved exactly as written.
709 EXPECT_THAT(getSymbols("foo.cpp"),
710 UnorderedElementsAre(
711 WithName("foo"), WithName("foo::bar::Cls"),
712 WithName("foo::bar::func1"), WithName("::foo::bar::func2"),
713 WithName("using namespace foo"), WithName("bar::func3"),
714 WithName("alias"), WithName("::alias::func4")));
715 }
716
717 TEST_F(DocumentSymbolsTest, QualifiersWithTemplateArgs) {
718 addFile("foo.cpp", R"cpp(
719 template <typename T, typename U = double> class Foo;
720
721 template <>
722 class Foo<int, double> {
723 int method1();
724 int method2();
725 int method3();
726 };
727
728 using int_type = int;
729
730 // Typedefs should be preserved!
731 int Foo<int_type, double>::method1() { return 10; }
732
733 // Default arguments should not be shown!
734 int Foo<int>::method2() { return 20; }
735
736 using Foo_type = Foo<int>;
737 // If the whole type is aliased, this should be preserved too!
738 int Foo_type::method3() { return 30; }
739 )cpp");
740 EXPECT_THAT(
741 getSymbols("foo.cpp"),
742 UnorderedElementsAre(WithName("Foo"), WithName("Foo<int, double>"),
743 WithName("int_type"),
744 WithName("Foo<int_type, double>::method1"),
745 WithName("Foo<int>::method2"), WithName("Foo_type"),
746 WithName("Foo_type::method3")));
747 }
748
749 } // namespace clangd
750 } // namespace clang
Limit
int Limit
Definition: FindSymbolsTests.cpp:71
clang::clangd::MATCHER_P
MATCHER_P(Named, N, "")
Definition: BackgroundIndexTests.cpp:26
clang::clangd::ClangdServer::addDocument
void addDocument(PathRef File, StringRef Contents, WantDiagnostics WD=WantDiagnostics::Auto)
Add a File to the list of tracked C++ files or update the contents if File is already tracked...
Definition: ClangdServer.cpp:157
Contents
llvm::StringRef Contents
Definition: CodeComplete.cpp:1021
clang::clangd::Annotations::range
clangd::Range range(llvm::StringRef Name="") const
Definition: Annotations.cpp:37
FindSymbols.h
ClangdServer.h
clang::clangd::MockFSProvider::Files
llvm::StringMap< std::string > Files
Definition: TestFS.h:38
clang::clangd::runDocumentSymbols
llvm::Expected< std::vector< DocumentSymbol > > runDocumentSymbols(ClangdServer &Server, PathRef File)
Definition: SyncAPI.cpp:120
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
clang::clangd::ClangdServer::blockUntilIdleForTest
LLVM_NODISCARD bool blockUntilIdleForTest(llvm::Optional< double > TimeoutSeconds=10)
Definition: ClangdServer.cpp:631
clang::clangd::ClangdServer::optsForTest
static Options optsForTest()
Definition: ClangdServer.cpp:103
TestFS.h
FSProvider
MockFSProvider FSProvider
Definition: FindSymbolsTests.cpp:67
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:57
clang::clangd::MockFSProvider
Definition: TestFS.h:31
clang::clangd::TEST_F
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
Definition: BackgroundIndexTests.cpp:88
clang::clangd::SymbolKind::Class
QName
std::string QName
Definition: DiagnosticsTests.cpp:523
Annotations.h
clang::clangd::testPath
std::string testPath(PathRef File)
Definition: TestFS.cpp:82
clang::clangd::CompletionItemKind::Field
clang::clangd::SymbolKind::Method
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
clang::clangd::DiagnosticsConsumer::onDiagnosticsReady
virtual void onDiagnosticsReady(PathRef File, std::vector< Diag > Diagnostics)=0
Called by ClangdServer when Diagnostics for File are ready.
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::clangd::testRoot
const char * testRoot()
Definition: TestFS.cpp:74
clang::clangd::IgnoreDiagnostics
Definition: Compiler.h:28
clang::clangd::DocumentSymbol::children
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
Definition: Protocol.h:822
FileName
PathRef FileName
Definition: CodeComplete.cpp:1018
clang::clangd::SymbolKind::Variable
clang::clangd::TypeHierarchyDirection::Children
clang::clangd::SymbolKind::String
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::runWorkspaceSymbols
llvm::Expected< std::vector< SymbolInformation > > runWorkspaceSymbols(ClangdServer &Server, llvm::StringRef Query, int Limit)
Definition: SyncAPI.cpp:113
Server
ClangdServer Server
Definition: FindSymbolsTests.cpp:70
CDB
MockCompilationDatabase CDB
Definition: FindSymbolsTests.cpp:68
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::SymbolKind::Function
clang::clangd::SymbolKind::Namespace
clang::clangd::Annotations
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges...
Definition: Annotations.h:23
clang::clangd::CompletionItemKind::Struct
SyncAPI.h
clang::clangd::MockCompilationDatabase
Definition: TestFS.h:42
DiagConsumer
IgnoreDiagnostics DiagConsumer
Definition: FindSymbolsTests.cpp:69
clang::clangd::ClangdServer
Manages a collection of source files and derived data (ASTs, indexes), and provides language-aware fe...
Definition: ClangdServer.h:80
clang::clangd::CompletionItemKind::File
clang::clangd::SymbolKind::Constructor