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