clang-tools  10.0.0svn
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 {
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.h", R"cpp(
182  namespace {
183  void test() {}
184  }
185  )cpp");
186  addFile("foo.cpp", R"cpp(
187  #include "foo.h"
188  )cpp");
189  EXPECT_THAT(getSymbols("test"), ElementsAre(QName("test")));
190 }
191 
192 TEST_F(WorkspaceSymbolsTest, MultiFile) {
193  addFile("foo.h", R"cpp(
194  int foo() {
195  }
196  )cpp");
197  addFile("foo2.h", R"cpp(
198  int foo2() {
199  }
200  )cpp");
201  addFile("foo.cpp", R"cpp(
202  #include "foo.h"
203  #include "foo2.h"
204  )cpp");
205  EXPECT_THAT(getSymbols("foo"),
206  UnorderedElementsAre(QName("foo"), QName("foo2")));
207 }
208 
209 TEST_F(WorkspaceSymbolsTest, GlobalNamespaceQueries) {
210  addFile("foo.h", R"cpp(
211  int foo() {
212  }
213  class Foo {
214  int a;
215  };
216  namespace ns {
217  int foo2() {
218  }
219  }
220  )cpp");
221  addFile("foo.cpp", R"cpp(
222  #include "foo.h"
223  )cpp");
224  EXPECT_THAT(getSymbols("::"),
225  UnorderedElementsAre(
226  AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
227  AllOf(QName("foo"), WithKind(SymbolKind::Function)),
228  AllOf(QName("ns"), WithKind(SymbolKind::Namespace))));
229  EXPECT_THAT(getSymbols(":"), IsEmpty());
230  EXPECT_THAT(getSymbols(""), IsEmpty());
231 }
232 
233 TEST_F(WorkspaceSymbolsTest, Enums) {
234  addFile("foo.h", R"cpp(
235  enum {
236  Red
237  };
238  enum Color {
239  Green
240  };
241  enum class Color2 {
242  Yellow
243  };
244  namespace ns {
245  enum {
246  Black
247  };
248  enum Color3 {
249  Blue
250  };
251  enum class Color4 {
252  White
253  };
254  }
255  )cpp");
256  addFile("foo.cpp", R"cpp(
257  #include "foo.h"
258  )cpp");
259  EXPECT_THAT(getSymbols("Red"), ElementsAre(QName("Red")));
260  EXPECT_THAT(getSymbols("::Red"), ElementsAre(QName("Red")));
261  EXPECT_THAT(getSymbols("Green"), ElementsAre(QName("Green")));
262  EXPECT_THAT(getSymbols("Green"), ElementsAre(QName("Green")));
263  EXPECT_THAT(getSymbols("Color2::Yellow"),
264  ElementsAre(QName("Color2::Yellow")));
265  EXPECT_THAT(getSymbols("Yellow"), ElementsAre(QName("Color2::Yellow")));
266 
267  EXPECT_THAT(getSymbols("ns::Black"), ElementsAre(QName("ns::Black")));
268  EXPECT_THAT(getSymbols("ns::Blue"), ElementsAre(QName("ns::Blue")));
269  EXPECT_THAT(getSymbols("ns::Color4::White"),
270  ElementsAre(QName("ns::Color4::White")));
271 }
272 
273 TEST_F(WorkspaceSymbolsTest, Ranking) {
274  addFile("foo.h", R"cpp(
275  namespace ns{}
276  void func();
277  )cpp");
278  addFile("foo.cpp", R"cpp(
279  #include "foo.h"
280  )cpp");
281  EXPECT_THAT(getSymbols("::"), ElementsAre(QName("func"), QName("ns")));
282 }
283 
284 TEST_F(WorkspaceSymbolsTest, WithLimit) {
285  addFile("foo.h", R"cpp(
286  int foo;
287  int foo2;
288  )cpp");
289  addFile("foo.cpp", R"cpp(
290  #include "foo.h"
291  )cpp");
292  // Foo is higher ranked because of exact name match.
293  EXPECT_THAT(getSymbols("foo"),
294  UnorderedElementsAre(
295  AllOf(QName("foo"), WithKind(SymbolKind::Variable)),
296  AllOf(QName("foo2"), WithKind(SymbolKind::Variable))));
297 
298  Limit = 1;
299  EXPECT_THAT(getSymbols("foo"), ElementsAre(QName("foo")));
300 }
301 
302 TEST_F(WorkspaceSymbolsTest, TempSpecs) {
303  addFile("foo.h", R"cpp(
304  template <typename T, typename U, int X = 5> class Foo {};
305  template <typename T> class Foo<int, T> {};
306  template <> class Foo<bool, int> {};
307  template <> class Foo<bool, int, 3> {};
308  )cpp");
309  // Foo is higher ranked because of exact name match.
310  EXPECT_THAT(
311  getSymbols("Foo"),
312  UnorderedElementsAre(
313  AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
314  AllOf(QName("Foo<int, T>"), WithKind(SymbolKind::Class)),
315  AllOf(QName("Foo<bool, int>"), WithKind(SymbolKind::Class)),
316  AllOf(QName("Foo<bool, int, 3>"), WithKind(SymbolKind::Class))));
317 }
318 
319 namespace {
320 class DocumentSymbolsTest : public ::testing::Test {
321 public:
322  DocumentSymbolsTest()
323  : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {}
324 
325 protected:
330 
331  std::vector<DocumentSymbol> getSymbols(PathRef File) {
332  EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
333  auto SymbolInfos = runDocumentSymbols(Server, File);
334  EXPECT_TRUE(bool(SymbolInfos)) << "documentSymbols returned an error";
335  return *SymbolInfos;
336  }
337 
338  void addFile(llvm::StringRef FilePath, llvm::StringRef Contents) {
339  FSProvider.Files[FilePath] = Contents;
340  Server.addDocument(FilePath, Contents);
341  }
342 };
343 } // namespace
344 
345 TEST_F(DocumentSymbolsTest, BasicSymbols) {
346  std::string FilePath = testPath("foo.cpp");
347  Annotations Main(R"(
348  class Foo;
349  class Foo {
350  Foo() {}
351  Foo(int a) {}
352  void $decl[[f]]();
353  friend void f1();
354  friend class Friend;
355  Foo& operator=(const Foo&);
356  ~Foo();
357  class Nested {
358  void f();
359  };
360  };
361  class Friend {
362  };
363 
364  void f1();
365  inline void f2() {}
366  static const int KInt = 2;
367  const char* kStr = "123";
368 
369  void f1() {}
370 
371  namespace foo {
372  // Type alias
373  typedef int int32;
374  using int32_t = int32;
375 
376  // Variable
377  int v1;
378 
379  // Namespace
380  namespace bar {
381  int v2;
382  }
383  // Namespace alias
384  namespace baz = bar;
385 
386  using bar::v2;
387  } // namespace foo
388  )");
389 
390  addFile(FilePath, Main.code());
391  EXPECT_THAT(
392  getSymbols(FilePath),
393  ElementsAreArray(
394  {AllOf(WithName("Foo"), WithKind(SymbolKind::Class), Children()),
395  AllOf(WithName("Foo"), WithKind(SymbolKind::Class),
396  Children(AllOf(WithName("Foo"), WithKind(SymbolKind::Method),
397  Children()),
398  AllOf(WithName("Foo"), WithKind(SymbolKind::Method),
399  Children()),
400  AllOf(WithName("f"), WithKind(SymbolKind::Method),
401  Children()),
402  AllOf(WithName("operator="),
403  WithKind(SymbolKind::Method), Children()),
404  AllOf(WithName("~Foo"), WithKind(SymbolKind::Method),
405  Children()),
406  AllOf(WithName("Nested"), WithKind(SymbolKind::Class),
407  Children(AllOf(WithName("f"),
408  WithKind(SymbolKind::Method),
409  Children()))))),
410  AllOf(WithName("Friend"), WithKind(SymbolKind::Class), Children()),
411  AllOf(WithName("f1"), WithKind(SymbolKind::Function), Children()),
412  AllOf(WithName("f2"), WithKind(SymbolKind::Function), Children()),
413  AllOf(WithName("KInt"), WithKind(SymbolKind::Variable), Children()),
414  AllOf(WithName("kStr"), WithKind(SymbolKind::Variable), Children()),
415  AllOf(WithName("f1"), WithKind(SymbolKind::Function), Children()),
416  AllOf(
417  WithName("foo"), WithKind(SymbolKind::Namespace),
418  Children(
419  AllOf(WithName("int32"), WithKind(SymbolKind::Class),
420  Children()),
421  AllOf(WithName("int32_t"), WithKind(SymbolKind::Class),
422  Children()),
423  AllOf(WithName("v1"), WithKind(SymbolKind::Variable),
424  Children()),
425  AllOf(WithName("bar"), WithKind(SymbolKind::Namespace),
426  Children(AllOf(WithName("v2"),
427  WithKind(SymbolKind::Variable),
428  Children()))),
429  AllOf(WithName("baz"), WithKind(SymbolKind::Namespace),
430  Children()),
431  AllOf(WithName("v2"), WithKind(SymbolKind::Namespace))))}));
432 }
433 
434 TEST_F(DocumentSymbolsTest, DeclarationDefinition) {
435  std::string FilePath = testPath("foo.cpp");
436  Annotations Main(R"(
437  class Foo {
438  void $decl[[f]]();
439  };
440  void Foo::$def[[f]]() {
441  }
442  )");
443 
444  addFile(FilePath, Main.code());
445  EXPECT_THAT(
446  getSymbols(FilePath),
447  ElementsAre(
448  AllOf(WithName("Foo"), WithKind(SymbolKind::Class),
449  Children(AllOf(WithName("f"), WithKind(SymbolKind::Method),
450  SymNameRange(Main.range("decl"))))),
451  AllOf(WithName("Foo::f"), WithKind(SymbolKind::Method),
452  SymNameRange(Main.range("def")))));
453 }
454 
455 TEST_F(DocumentSymbolsTest, ExternSymbol) {
456  std::string FilePath = testPath("foo.cpp");
457  addFile(testPath("foo.h"), R"cpp(
458  extern int var;
459  )cpp");
460  addFile(FilePath, R"cpp(
461  #include "foo.h"
462  )cpp");
463 
464  EXPECT_THAT(getSymbols(FilePath), IsEmpty());
465 }
466 
467 TEST_F(DocumentSymbolsTest, NoLocals) {
468  std::string FilePath = testPath("foo.cpp");
469  addFile(FilePath,
470  R"cpp(
471  void test(int FirstParam, int SecondParam) {
472  struct LocalClass {};
473  int local_var;
474  })cpp");
475  EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test")));
476 }
477 
478 TEST_F(DocumentSymbolsTest, Unnamed) {
479  std::string FilePath = testPath("foo.h");
480  addFile(FilePath,
481  R"cpp(
482  struct {
483  int InUnnamed;
484  } UnnamedStruct;
485  )cpp");
486  EXPECT_THAT(
487  getSymbols(FilePath),
488  ElementsAre(
489  AllOf(WithName("(anonymous struct)"), WithKind(SymbolKind::Struct),
490  Children(AllOf(WithName("InUnnamed"),
491  WithKind(SymbolKind::Field), Children()))),
492  AllOf(WithName("UnnamedStruct"), WithKind(SymbolKind::Variable),
493  Children())));
494 }
495 
496 TEST_F(DocumentSymbolsTest, InHeaderFile) {
497  addFile(testPath("bar.h"), R"cpp(
498  int foo() {
499  }
500  )cpp");
501  std::string FilePath = testPath("foo.h");
502  addFile(FilePath, R"cpp(
503  #include "bar.h"
504  int test() {
505  }
506  )cpp");
507  addFile(testPath("foo.cpp"), R"cpp(
508  #include "foo.h"
509  )cpp");
510  EXPECT_THAT(getSymbols(FilePath), ElementsAre(WithName("test")));
511 }
512 
513 TEST_F(DocumentSymbolsTest, Template) {
514  std::string FilePath = testPath("foo.cpp");
515  addFile(FilePath, R"(
516  template <class T> struct Tmpl {T x = 0;};
517  template <> struct Tmpl<int> {
518  int y = 0;
519  };
520  extern template struct Tmpl<float>;
521  template struct Tmpl<double>;
522 
523  template <class T, class U, class Z = float>
524  int funcTmpl(U a);
525  template <>
526  int funcTmpl<int>(double a);
527 
528  template <class T, class U = double>
529  int varTmpl = T();
530  template <>
531  double varTmpl<int> = 10.0;
532  )");
533  EXPECT_THAT(
534  getSymbols(FilePath),
535  ElementsAre(
536  AllOf(WithName("Tmpl"), WithKind(SymbolKind::Struct),
537  Children(AllOf(WithName("x"), WithKind(SymbolKind::Field)))),
538  AllOf(WithName("Tmpl<int>"), WithKind(SymbolKind::Struct),
539  Children(WithName("y"))),
540  AllOf(WithName("Tmpl<float>"), WithKind(SymbolKind::Struct),
541  Children()),
542  AllOf(WithName("Tmpl<double>"), WithKind(SymbolKind::Struct),
543  Children()),
544  AllOf(WithName("funcTmpl"), Children()),
545  AllOf(WithName("funcTmpl<int>"), Children()),
546  AllOf(WithName("varTmpl"), Children()),
547  AllOf(WithName("varTmpl<int>"), Children())));
548 }
549 
550 TEST_F(DocumentSymbolsTest, Namespaces) {
551  std::string FilePath = testPath("foo.cpp");
552  addFile(FilePath, R"cpp(
553  namespace ans1 {
554  int ai1;
555  namespace ans2 {
556  int ai2;
557  }
558  }
559  namespace {
560  void test() {}
561  }
562 
563  namespace na {
564  inline namespace nb {
565  class Foo {};
566  }
567  }
568  namespace na {
569  // This is still inlined.
570  namespace nb {
571  class Bar {};
572  }
573  }
574  )cpp");
575  EXPECT_THAT(
576  getSymbols(FilePath),
577  ElementsAreArray<::testing::Matcher<DocumentSymbol>>(
578  {AllOf(WithName("ans1"),
579  Children(AllOf(WithName("ai1"), Children()),
580  AllOf(WithName("ans2"), Children(WithName("ai2"))))),
581  AllOf(WithName("(anonymous namespace)"), Children(WithName("test"))),
582  AllOf(WithName("na"),
583  Children(AllOf(WithName("nb"), Children(WithName("Foo"))))),
584  AllOf(WithName("na"),
585  Children(AllOf(WithName("nb"), Children(WithName("Bar")))))}));
586 }
587 
588 TEST_F(DocumentSymbolsTest, Enums) {
589  std::string FilePath = testPath("foo.cpp");
590  addFile(FilePath, R"(
591  enum {
592  Red
593  };
594  enum Color {
595  Green
596  };
597  enum class Color2 {
598  Yellow
599  };
600  namespace ns {
601  enum {
602  Black
603  };
604  }
605  )");
606  EXPECT_THAT(
607  getSymbols(FilePath),
608  ElementsAre(
609  AllOf(WithName("(anonymous enum)"), Children(WithName("Red"))),
610  AllOf(WithName("Color"), Children(WithName("Green"))),
611  AllOf(WithName("Color2"), Children(WithName("Yellow"))),
612  AllOf(WithName("ns"), Children(AllOf(WithName("(anonymous enum)"),
613  Children(WithName("Black")))))));
614 }
615 
616 TEST_F(DocumentSymbolsTest, FromMacro) {
617  std::string FilePath = testPath("foo.cpp");
618  Annotations Main(R"(
619  #define FF(name) \
620  class name##_Test {};
621 
622  $expansion[[FF]](abc);
623 
624  #define FF2() \
625  class $spelling[[Test]] {};
626 
627  FF2();
628  )");
629  addFile(FilePath, Main.code());
630  EXPECT_THAT(
631  getSymbols(FilePath),
632  ElementsAre(
633  AllOf(WithName("abc_Test"), SymNameRange(Main.range("expansion"))),
634  AllOf(WithName("Test"), SymNameRange(Main.range("spelling")))));
635 }
636 
637 TEST_F(DocumentSymbolsTest, FuncTemplates) {
638  std::string FilePath = testPath("foo.cpp");
639  Annotations Source(R"cpp(
640  template <class T>
641  T foo() {}
642 
643  auto x = foo<int>();
644  auto y = foo<double>()
645  )cpp");
646  addFile(FilePath, Source.code());
647  // Make sure we only see the template declaration, not instantiations.
648  EXPECT_THAT(getSymbols(FilePath),
649  ElementsAre(WithName("foo"), WithName("x"), WithName("y")));
650 }
651 
652 TEST_F(DocumentSymbolsTest, UsingDirectives) {
653  std::string FilePath = testPath("foo.cpp");
654  Annotations Source(R"cpp(
655  namespace ns {
656  int foo;
657  }
658 
659  namespace ns_alias = ns;
660 
661  using namespace ::ns; // check we don't loose qualifiers.
662  using namespace ns_alias; // and namespace aliases.
663  )cpp");
664  addFile(FilePath, Source.code());
665  EXPECT_THAT(getSymbols(FilePath),
666  ElementsAre(WithName("ns"), WithName("ns_alias"),
667  WithName("using namespace ::ns"),
668  WithName("using namespace ns_alias")));
669 }
670 
671 TEST_F(DocumentSymbolsTest, TempSpecs) {
672  addFile("foo.cpp", R"cpp(
673  template <typename T, typename U, int X = 5> class Foo {};
674  template <typename T> class Foo<int, T> {};
675  template <> class Foo<bool, int> {};
676  template <> class Foo<bool, int, 3> {};
677  )cpp");
678  // Foo is higher ranked because of exact name match.
679  EXPECT_THAT(
680  getSymbols("foo.cpp"),
681  UnorderedElementsAre(
682  AllOf(WithName("Foo"), WithKind(SymbolKind::Class)),
683  AllOf(WithName("Foo<int, T>"), WithKind(SymbolKind::Class)),
684  AllOf(WithName("Foo<bool, int>"), WithKind(SymbolKind::Class)),
685  AllOf(WithName("Foo<bool, int, 3>"), WithKind(SymbolKind::Class))));
686 }
687 
688 TEST_F(DocumentSymbolsTest, Qualifiers) {
689  addFile("foo.cpp", R"cpp(
690  namespace foo { namespace bar {
691  struct Cls;
692 
693  int func1();
694  int func2();
695  int func3();
696  int func4();
697  }}
698 
699  struct foo::bar::Cls { };
700 
701  int foo::bar::func1() { return 10; }
702  int ::foo::bar::func2() { return 20; }
703 
704  using namespace foo;
705  int bar::func3() { return 30; }
706 
707  namespace alias = foo::bar;
708  int ::alias::func4() { return 40; }
709  )cpp");
710 
711  // All the qualifiers should be preserved exactly as written.
712  EXPECT_THAT(getSymbols("foo.cpp"),
713  UnorderedElementsAre(
714  WithName("foo"), WithName("foo::bar::Cls"),
715  WithName("foo::bar::func1"), WithName("::foo::bar::func2"),
716  WithName("using namespace foo"), WithName("bar::func3"),
717  WithName("alias"), WithName("::alias::func4")));
718 }
719 
720 TEST_F(DocumentSymbolsTest, QualifiersWithTemplateArgs) {
721  addFile("foo.cpp", R"cpp(
722  template <typename T, typename U = double> class Foo;
723 
724  template <>
725  class Foo<int, double> {
726  int method1();
727  int method2();
728  int method3();
729  };
730 
731  using int_type = int;
732 
733  // Typedefs should be preserved!
734  int Foo<int_type, double>::method1() { return 10; }
735 
736  // Default arguments should not be shown!
737  int Foo<int>::method2() { return 20; }
738 
739  using Foo_type = Foo<int>;
740  // If the whole type is aliased, this should be preserved too!
741  int Foo_type::method3() { return 30; }
742  )cpp");
743  EXPECT_THAT(
744  getSymbols("foo.cpp"),
745  UnorderedElementsAre(WithName("Foo"), WithName("Foo<int, double>"),
746  WithName("int_type"),
747  WithName("Foo<int_type, double>::method1"),
748  WithName("Foo<int>::method2"), WithName("Foo_type"),
749  WithName("Foo_type::method3")));
750 }
751 
752 } // namespace clangd
753 } // namespace clang
int Limit
MATCHER_P(Named, N, "")
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...
llvm::StringRef Contents
clangd::Range range(llvm::StringRef Name="") const
Definition: Annotations.cpp:37
llvm::StringMap< std::string > Files
Definition: TestFS.h:38
llvm::Expected< std::vector< DocumentSymbol > > runDocumentSymbols(ClangdServer &Server, PathRef File)
Definition: SyncAPI.cpp:121
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
LLVM_NODISCARD bool blockUntilIdleForTest(llvm::Optional< double > TimeoutSeconds=10)
static Options optsForTest()
MockFSProvider FSProvider
BindArgumentKind Kind
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
std::string QName
std::string testPath(PathRef File)
Definition: TestFS.cpp:82
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
virtual void onDiagnosticsReady(PathRef File, std::vector< Diag > Diagnostics)=0
Called by ClangdServer when Diagnostics for File are ready.
static constexpr llvm::StringLiteral Name
const char * testRoot()
Definition: TestFS.cpp:74
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
Definition: Protocol.h:822
PathRef FileName
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Expected< std::vector< SymbolInformation > > runWorkspaceSymbols(ClangdServer &Server, llvm::StringRef Query, int Limit)
Definition: SyncAPI.cpp:114
ClangdServer Server
MockCompilationDatabase CDB
CharSourceRange Range
SourceRange for the file name.
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges...
Definition: Annotations.h:23
IgnoreDiagnostics DiagConsumer
Manages a collection of source files and derived data (ASTs, indexes), and provides language-aware fe...
Definition: ClangdServer.h:78