1 //===-- FindSymbolsTests.cpp -------------------------*- C++ -*------------===//
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
7 //===----------------------------------------------------------------------===//
8 #include "Annotations.h"
9 #include "FindSymbols.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
21 using ::testing::AllOf
;
22 using ::testing::ElementsAre
;
23 using ::testing::ElementsAreArray
;
24 using ::testing::Field
;
25 using ::testing::IsEmpty
;
26 using ::testing::UnorderedElementsAre
;
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
;
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
; }
39 // GMock helpers for matching DocumentSymbol.
40 MATCHER_P(symNameRange
, Range
, "") { return arg
.selectionRange
== Range
; }
41 template <class... ChildMatchers
>
42 ::testing::Matcher
<DocumentSymbol
> children(ChildMatchers
... ChildrenM
) {
43 return Field(&DocumentSymbol::children
, UnorderedElementsAre(ChildrenM
...));
46 std::vector
<SymbolInformation
> getSymbols(TestTU
&TU
, llvm::StringRef Query
,
48 auto SymbolInfos
= getWorkspaceSymbols(Query
, Limit
, TU
.index().get(),
49 testPath(TU
.Filename
));
50 EXPECT_TRUE(bool(SymbolInfos
)) << "workspaceSymbols returned an error";
54 TEST(WorkspaceSymbols
, Macros
) {
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
))));
67 TEST(WorkspaceSymbols
, NoLocals
) {
70 void test(int FirstParam, int SecondParam) {
74 EXPECT_THAT(getSymbols(TU
, "l"), ElementsAre(qName("LocalClass")));
75 EXPECT_THAT(getSymbols(TU
, "p"), IsEmpty());
78 TEST(WorkspaceSymbols
, Globals
) {
80 TU
.AdditionalFiles
["foo.h"] = R
"cpp(
85 struct GlobalStruct {};)cpp";
89 EXPECT_THAT(getSymbols(TU
, "global"),
91 AllOf(qName("GlobalStruct"), withKind(SymbolKind::Struct
)),
92 AllOf(qName("global_func"), withKind(SymbolKind::Function
)),
93 AllOf(qName("global_var"), withKind(SymbolKind::Variable
))));
96 TEST(WorkspaceSymbols
, Unnamed
) {
98 TU
.AdditionalFiles
["foo.h"] = R
"cpp(
101 } UnnamedStruct;)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
))));
113 TEST(WorkspaceSymbols
, InMainFile
) {
117 static void test2() {}
119 EXPECT_THAT(getSymbols(TU
, "test"),
120 ElementsAre(qName("test"), qName("test2")));
123 TEST(WorkspaceSymbols
, Namespaces
) {
125 TU
.AdditionalFiles
["foo.h"] = R
"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")));
162 // Ensure sub-sequence matching works.
163 EXPECT_THAT(getSymbols(TU
, "ans1::ans3::ai"),
164 UnorderedElementsAre(qName("ans1::ans2::ans3::ai3")));
167 TEST(WorkspaceSymbols
, AnonymousNamespace
) {
174 EXPECT_THAT(getSymbols(TU
, "test"), ElementsAre(qName("test")));
177 TEST(WorkspaceSymbols
, MultiFile
) {
179 TU
.AdditionalFiles
["foo.h"] = R
"cpp(
183 TU
.AdditionalFiles
["foo2.h"] = R
"cpp(
191 EXPECT_THAT(getSymbols(TU
, "foo"),
192 UnorderedElementsAre(qName("foo"), qName("foo2")));
195 TEST(WorkspaceSymbols
, GlobalNamespaceQueries
) {
197 TU
.AdditionalFiles
["foo.h"] = R
"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")));
222 TEST(WorkspaceSymbols
, Enums
) {
224 TU
.AdditionalFiles
["foo.h"] = R
"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")));
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")));
263 TEST(WorkspaceSymbols
, Ranking
) {
265 TU
.AdditionalFiles
["foo.h"] = R
"cpp(
272 EXPECT_THAT(getSymbols(TU
, "::"), ElementsAre(qName("func"), qName("ns")));
275 TEST(WorkspaceSymbols
, RankingPartialNamespace
) {
279 namespace ns2 { struct Foo {}; }
281 namespace ns2 { struct FooB {}; })cpp";
282 EXPECT_THAT(getSymbols(TU
, "ns2::f"),
283 ElementsAre(qName("ns2::FooB"), qName("ns1::ns2::Foo")));
286 TEST(WorkspaceSymbols
, WithLimit
) {
288 TU
.AdditionalFiles
["foo.h"] = R
"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
))));
301 EXPECT_THAT(getSymbols(TU
, "foo", 1), ElementsAre(qName("foo")));
304 TEST(WorkspaceSymbols
, TempSpecs
) {
306 TU
.ExtraArgs
= {"-xc++"};
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> {};
313 // Foo is higher ranked because of exact name match.
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
))));
323 std::vector
<DocumentSymbol
> getSymbols(ParsedAST AST
) {
324 auto SymbolInfos
= getDocumentSymbols(AST
);
325 EXPECT_TRUE(bool(SymbolInfos
)) << "documentSymbols returned an error";
329 TEST(DocumentSymbols
, BasicSymbols
) {
339 Foo& operator=(const Foo&);
350 static const int KInt = 2;
351 const char* kStr = "123";
358 using int32_t = int32;
374 TU
.Code
= Main
.code().str();
376 getSymbols(TU
.build()),
378 {AllOf(withName("Foo"), withKind(SymbolKind::Class
),
379 withDetail("class"), children()),
380 AllOf(withName("Foo"), withKind(SymbolKind::Class
),
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
),
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()),
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
),
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(""))))}));
429 TEST(DocumentSymbols
, DeclarationDefinition
) {
435 void Foo::$def[[f]]() {
439 TU
.Code
= Main
.code().str();
441 getSymbols(TU
.build()),
443 AllOf(withName("Foo"), withKind(SymbolKind::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")))));
452 TEST(DocumentSymbols
, Concepts
) {
454 TU
.ExtraArgs
= {"-std=c++20"};
455 TU
.Code
= "template <typename T> concept C = requires(T t) { t.foo(); };";
457 EXPECT_THAT(getSymbols(TU
.build()),
458 ElementsAre(AllOf(withName("C"), withDetail("concept"))));
461 TEST(DocumentSymbols
, ExternSymbol
) {
463 TU
.AdditionalFiles
["foo.h"] = R
"cpp(
470 EXPECT_THAT(getSymbols(TU
.build()), IsEmpty());
473 TEST(DocumentSymbols
, ExternContext
) {
487 EXPECT_THAT(getSymbols(TU
.build()),
488 ElementsAre(withName("foo"), withName("Foo"),
489 AllOf(withName("ns"),
490 children(withName("bar"), withName("Bar")))));
493 TEST(DocumentSymbols
, ExportContext
) {
495 TU
.ExtraArgs
= {"-std=c++20"};
503 EXPECT_THAT(getSymbols(TU
.build()),
504 ElementsAre(withName("foo"), withName("Foo")));
507 TEST(DocumentSymbols
, NoLocals
) {
510 void test(int FirstParam, int SecondParam) {
511 struct LocalClass {};
514 EXPECT_THAT(getSymbols(TU
.build()), ElementsAre(withName("test")));
517 TEST(DocumentSymbols
, Unnamed
) {
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())));
536 TEST(DocumentSymbols
, InHeaderFile
) {
538 TU
.AdditionalFiles
["bar.h"] = R
"cpp(
543 int i; // declaration to finish preamble
548 EXPECT_THAT(getSymbols(TU
.build()),
549 ElementsAre(withName("i"), withName("test")));
552 TEST(DocumentSymbols
, Template
) {
555 template <class T> struct Tmpl {T x = 0;};
556 template <> struct Tmpl<int> {
559 extern template struct Tmpl<float>;
560 template struct Tmpl<double>;
562 template <class T, class U, class Z = float>
565 int funcTmpl<int>(double a);
567 template <class T, class U = double>
570 double varTmpl<int> = 10.0;
573 getSymbols(TU
.build()),
575 AllOf(withName("Tmpl"), withKind(SymbolKind::Struct
),
576 withDetail("template struct"),
577 children(AllOf(withName("x"), withKind(SymbolKind::Field
),
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)"),
588 AllOf(withName("funcTmpl<int>"), withDetail("int (double)"),
590 AllOf(withName("varTmpl"), withDetail("template int"), children()),
591 AllOf(withName("varTmpl<int>"), withDetail("double"), children())));
594 TEST(DocumentSymbols
, Namespaces
) {
608 inline namespace nb {
613 // This is still inlined.
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")))))}));
632 TEST(DocumentSymbols
, Enums
) {
651 getSymbols(TU
.build()),
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)"))))))));
665 TEST(DocumentSymbols
, Macro
) {
668 testing::Matcher
<DocumentSymbol
> Matcher
;
672 // Basic macro that generates symbols.
673 #define DEFINE_FLAG(X) bool FLAGS_##X; bool FLAGS_no##X
676 AllOf(withName("DEFINE_FLAG"), withDetail("(pretty)"),
677 children(withName("FLAGS_pretty"), withName("FLAGS_nopretty"))),
681 // Hierarchy is determined by primary (name) location.
683 namespace ID(ns) { int ID(y); }
685 AllOf(withName("ID"), withDetail("(ns)"),
686 children(AllOf(withName("ns"),
687 children(AllOf(withName("ID"), withDetail("(y)"),
688 children(withName("y"))))))),
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) { }
696 AllOf(withName("TEST"), withDetail("(DocumentSymbols, Macro)"),
697 children(AllOf(withName("DocumentSymbols_Macro"),
698 children(withName("go"))),
699 withName("DocumentSymbols_Macro::go"))),
704 #define NAMESPACE(NS, BODY) namespace NS { BODY }
705 NAMESPACE(a, NAMESPACE(b, int x;))
708 withName("NAMESPACE"), withDetail("(a, NAMESPACE(b, int x;))"),
711 children(AllOf(withName("NAMESPACE"),
712 // FIXME: nested expansions not in TokenBuffer
714 children(AllOf(withName("b"),
715 children(withName("x"))))))))),
719 // Macro invoked from body is not exposed.
720 #define INNER(X) int X
721 #define OUTER(X) INNER(X)
724 AllOf(withName("OUTER"), withDetail("(foo)"),
725 children(withName("foo"))),
728 for (const Test
&T
: Tests
) {
729 auto TU
= TestTU::withCode(T
.Code
);
730 EXPECT_THAT(getSymbols(TU
.build()), ElementsAre(T
.Matcher
)) << T
.Code
;
734 TEST(DocumentSymbols
, RangeFromMacro
) {
738 class name##_Test {};
740 $expansion1[[FF]](abc);
745 $expansion2parens[[$expansion2[[FF2]]()]];
754 TU
.Code
= Main
.code().str();
756 getSymbols(TU
.build()),
758 AllOf(withName("FF"), withDetail("(abc)"),
759 children(AllOf(withName("abc_Test"), withDetail("class"),
760 symNameRange(Main
.range("expansion1"))))),
761 AllOf(withName("FF2"), withDetail("()"),
762 symNameRange(Main
.range("expansion2")),
763 symRange(Main
.range("expansion2parens")),
764 children(AllOf(withName("Test"), withDetail("class"),
765 symNameRange(Main
.range("expansion2"))))),
766 AllOf(withName("FF3"), withDetail("()"),
767 symRange(Main
.range("fullDef")),
768 children(AllOf(withName("waldo"), withDetail("void ()"),
769 symRange(Main
.range("fullDef")))))));
772 TEST(DocumentSymbols
, FuncTemplates
) {
774 Annotations
Source(R
"cpp(
779 auto y = foo<double>();
781 TU
.Code
= Source
.code().str();
782 // Make sure we only see the template declaration, not instantiations.
783 EXPECT_THAT(getSymbols(TU
.build()),
784 ElementsAre(AllOf(withName("foo"), withDetail("template T ()")),
785 AllOf(withName("x"), withDetail("int")),
786 AllOf(withName("y"), withDetail("double"))));
789 TEST(DocumentSymbols
, UsingDirectives
) {
791 Annotations
Source(R
"cpp(
796 namespace ns_alias = ns;
798 using namespace ::ns; // check we don't loose qualifiers.
799 using namespace ns_alias; // and namespace aliases.
801 TU
.Code
= Source
.code().str();
802 EXPECT_THAT(getSymbols(TU
.build()),
803 ElementsAre(withName("ns"), withName("ns_alias"),
804 withName("using namespace ::ns"),
805 withName("using namespace ns_alias")));
808 TEST(DocumentSymbols
, TempSpecs
) {
811 template <typename T, typename U, int X = 5> class Foo {};
812 template <typename T> class Foo<int, T> {};
813 template <> class Foo<bool, int> {};
814 template <> class Foo<bool, int, 3> {};
816 // Foo is higher ranked because of exact name match.
817 EXPECT_THAT(getSymbols(TU
.build()),
818 UnorderedElementsAre(
819 AllOf(withName("Foo"), withKind(SymbolKind::Class
),
820 withDetail("template class")),
821 AllOf(withName("Foo<int, T>"), withKind(SymbolKind::Class
),
822 withDetail("template class")),
823 AllOf(withName("Foo<bool, int>"), withKind(SymbolKind::Class
),
824 withDetail("class")),
825 AllOf(withName("Foo<bool, int, 3>"),
826 withKind(SymbolKind::Class
), withDetail("class"))));
829 TEST(DocumentSymbols
, Qualifiers
) {
832 namespace foo { namespace bar {
841 struct foo::bar::Cls { };
843 int foo::bar::func1() { return 10; }
844 int ::foo::bar::func2() { return 20; }
847 int bar::func3() { return 30; }
849 namespace alias = foo::bar;
850 int ::alias::func4() { return 40; }
853 // All the qualifiers should be preserved exactly as written.
854 EXPECT_THAT(getSymbols(TU
.build()),
855 UnorderedElementsAre(
856 withName("foo"), withName("foo::bar::Cls"),
857 withName("foo::bar::func1"), withName("::foo::bar::func2"),
858 withName("using namespace foo"), withName("bar::func3"),
859 withName("alias"), withName("::alias::func4")));
862 TEST(DocumentSymbols
, QualifiersWithTemplateArgs
) {
865 template <typename T, typename U = double> class Foo;
868 class Foo<int, double> {
874 using int_type = int;
876 // Typedefs should be preserved!
877 int Foo<int_type, double>::method1() { return 10; }
879 // Default arguments should not be shown!
880 int Foo<int>::method2() { return 20; }
882 using Foo_type = Foo<int>;
883 // If the whole type is aliased, this should be preserved too!
884 int Foo_type::method3() { return 30; }
886 EXPECT_THAT(getSymbols(TU
.build()),
887 UnorderedElementsAre(
888 AllOf(withName("Foo"), withDetail("template class")),
889 AllOf(withName("Foo<int, double>"), withDetail("class")),
890 AllOf(withName("int_type"), withDetail("type alias")),
891 AllOf(withName("Foo<int_type, double>::method1"),
892 withDetail("int ()")),
893 AllOf(withName("Foo<int>::method2"), withDetail("int ()")),
894 AllOf(withName("Foo_type"), withDetail("type alias")),
895 AllOf(withName("Foo_type::method3"), withDetail("int ()"))));
898 TEST(DocumentSymbolsTest
, Ranges
) {
901 $foo[[int foo(bool Argument) {
905 $variable[[char GLOBAL_VARIABLE]];
914 $field[[unsigned Baz]];
916 $getbaz[[unsigned getBaz() { return Baz; }]]
920 $forwardclass[[class ForwardClassDecl]];
922 $struct[[struct StructDefinition {
923 $structfield[[int *Pointer = nullptr]];
925 $forwardstruct[[struct StructDeclaration]];
927 $forwardfunc[[void forwardFunctionDecl(int Something)]];
929 TU
.Code
= Main
.code().str();
931 getSymbols(TU
.build()),
932 UnorderedElementsAre(
933 AllOf(withName("foo"), withKind(SymbolKind::Function
),
934 withDetail("int (bool)"), symRange(Main
.range("foo"))),
935 AllOf(withName("GLOBAL_VARIABLE"), withKind(SymbolKind::Variable
),
936 withDetail("char"), symRange(Main
.range("variable"))),
938 withName("ns"), withKind(SymbolKind::Namespace
),
939 symRange(Main
.range("ns")),
941 withName("Bar"), withKind(SymbolKind::Class
),
942 withDetail("class"), symRange(Main
.range("bar")),
944 AllOf(withName("Bar"), withKind(SymbolKind::Constructor
),
945 withDetail("()"), symRange(Main
.range("ctor"))),
946 AllOf(withName("~Bar"), withKind(SymbolKind::Constructor
),
947 withDetail(""), symRange(Main
.range("dtor"))),
948 AllOf(withName("Baz"), withKind(SymbolKind::Field
),
949 withDetail("unsigned int"),
950 symRange(Main
.range("field"))),
951 AllOf(withName("getBaz"), withKind(SymbolKind::Method
),
952 withDetail("unsigned int ()"),
953 symRange(Main
.range("getbaz"))))))),
954 AllOf(withName("ForwardClassDecl"), withKind(SymbolKind::Class
),
955 withDetail("class"), symRange(Main
.range("forwardclass"))),
956 AllOf(withName("StructDefinition"), withKind(SymbolKind::Struct
),
957 withDetail("struct"), symRange(Main
.range("struct")),
958 children(AllOf(withName("Pointer"), withKind(SymbolKind::Field
),
960 symRange(Main
.range("structfield"))))),
961 AllOf(withName("StructDeclaration"), withKind(SymbolKind::Struct
),
962 withDetail("struct"), symRange(Main
.range("forwardstruct"))),
963 AllOf(withName("forwardFunctionDecl"), withKind(SymbolKind::Function
),
964 withDetail("void (int)"),
965 symRange(Main
.range("forwardfunc")))));
968 TEST(DocumentSymbolsTest
, DependentType
) {
971 template <typename T> auto plus(T x, T y) -> decltype(x + y) { return x + y; }
973 template <typename Key, typename Value> class Pair {};
975 template <typename Key, typename Value>
976 struct Context : public Pair<Key, Value> {
977 using Pair<Key, Value>::Pair;
981 getSymbols(TU
.build()),
983 AllOf(withName("plus"),
984 withDetail("template auto (T, T) -> decltype(x + y)")),
985 AllOf(withName("Pair"), withDetail("template class")),
986 AllOf(withName("Context"), withDetail("template struct"),
988 withName("Pair<type-parameter-0-0, type-parameter-0-1>"),
989 withDetail("<dependent type>"))))));
992 TEST(DocumentSymbolsTest
, ObjCCategoriesAndClassExtensions
) {
994 TU
.ExtraArgs
= {"-xobjective-c++", "-Wno-objc-root-class"};
995 Annotations
Main(R
"cpp(
999 $SneakyCat[[@interface Cat (Sneaky)
1000 - (id)sneak:(id)behavior;
1003 $MeowCat[[@interface Cat ()
1006 $PurCat[[@interface Cat ()
1010 TU
.Code
= Main
.code().str();
1012 getSymbols(TU
.build()),
1014 AllOf(withName("Cat"), symRange(Main
.range("Cat")),
1015 children(AllOf(withName("+sharedCat"),
1016 withKind(SymbolKind::Method
)))),
1017 AllOf(withName("Cat(Sneaky)"), symRange(Main
.range("SneakyCat")),
1019 AllOf(withName("-sneak:"), withKind(SymbolKind::Method
)))),
1021 withName("Cat()"), symRange(Main
.range("MeowCat")),
1022 children(AllOf(withName("-meow"), withKind(SymbolKind::Method
)))),
1023 AllOf(withName("Cat()"), symRange(Main
.range("PurCat")),
1025 AllOf(withName("-pur"), withKind(SymbolKind::Method
))))));
1028 TEST(DocumentSymbolsTest
, PragmaMarkGroups
) {
1030 TU
.ExtraArgs
= {"-xobjective-c++", "-Wno-objc-root-class"};
1031 Annotations
Main(R
"cpp(
1032 $DogDef[[@interface Dog
1035 $DogImpl[[@implementation Dog
1037 + (id)sharedDoggo { return 0; }
1039 #pragma $Overrides[[mark - Overrides
1046 #pragma $Specifics[[mark - Dog Specifics
1051 @]]end // FIXME: Why doesn't this include the 'end'?
1053 #pragma $End[[mark - End
1056 TU
.Code
= Main
.code().str();
1058 getSymbols(TU
.build()),
1059 UnorderedElementsAre(
1060 AllOf(withName("Dog"), symRange(Main
.range("DogDef"))),
1061 AllOf(withName("Dog"), symRange(Main
.range("DogImpl")),
1062 children(AllOf(withName("+sharedDoggo"),
1063 withKind(SymbolKind::Method
)),
1064 AllOf(withName("Overrides"),
1065 symRange(Main
.range("Overrides")),
1066 children(AllOf(withName("-init"),
1067 withKind(SymbolKind::Method
)),
1068 AllOf(withName("-bark"),
1069 withKind(SymbolKind::Method
)))),
1070 AllOf(withName("Dog Specifics"),
1071 symRange(Main
.range("Specifics")),
1072 children(AllOf(withName("-isAGoodBoy"),
1073 withKind(SymbolKind::Method
)))))),
1074 AllOf(withName("End"), symRange(Main
.range("End")))));
1077 TEST(DocumentSymbolsTest
, PragmaMarkGroupsNesting
) {
1079 TU
.ExtraArgs
= {"-xobjective-c++", "-Wno-objc-root-class"};
1080 Annotations
Main(R
"cpp(
1085 #pragma mark - NotTopDecl
1090 TU
.Code
= Main
.code().str();
1092 getSymbols(TU
.build()),
1093 UnorderedElementsAre(AllOf(
1095 children(AllOf(withName("Foo"),
1096 children(AllOf(withName("Bar"),
1097 children(AllOf(withName("bar"),
1099 "NotTopDecl"))))))),
1100 withName("bar")))));
1103 TEST(DocumentSymbolsTest
, PragmaMarkGroupsNoNesting
) {
1105 TU
.ExtraArgs
= {"-xobjective-c++", "-Wno-objc-root-class"};
1106 Annotations
Main(R
"cpp(
1107 #pragma mark Helpers
1108 void helpA(id obj) {}
1113 void coreMethod() {}
1115 TU
.Code
= Main
.code().str();
1116 EXPECT_THAT(getSymbols(TU
.build()),
1117 UnorderedElementsAre(withName("Helpers"), withName("helpA"),
1118 withName("(unnamed group)"),
1119 withName("Core"), withName("coreMethod")));
1123 } // namespace clangd
1124 } // namespace clang