brintos

brintos / llvm-project-archived public Read only

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