malaperle updated this revision to Diff 146391.
malaperle added a comment.
Herald added a subscriber: jkorous.

Rework to include member vars/functions and scoped enumerators.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D44954

Files:
  clangd/CodeComplete.cpp
  clangd/index/Index.h
  clangd/index/MemIndex.cpp
  clangd/index/SymbolCollector.cpp
  clangd/index/SymbolYAML.cpp
  unittests/clangd/CodeCompleteTests.cpp
  unittests/clangd/FileIndexTests.cpp
  unittests/clangd/FindSymbolsTests.cpp
  unittests/clangd/SymbolCollectorTests.cpp

Index: unittests/clangd/SymbolCollectorTests.cpp
===================================================================
--- unittests/clangd/SymbolCollectorTests.cpp
+++ unittests/clangd/SymbolCollectorTests.cpp
@@ -67,6 +67,9 @@
                   Pos.end.character);
 }
 MATCHER_P(Refs, R, "") { return int(arg.References) == R; }
+MATCHER_P(InScopedEnum, InScopedEnum, "") {
+  return arg.InScopedEnum == InScopedEnum;
+}
 
 namespace clang {
 namespace clangd {
@@ -198,25 +201,28 @@
     } // namespace foo
   )";
   runSymbolCollector(Header, /*Main=*/"");
-  EXPECT_THAT(Symbols,
-              UnorderedElementsAreArray(
-                  {QName("Foo"), QName("f1"), QName("f2"), QName("KInt"),
-                   QName("kStr"), QName("foo"), QName("foo::bar"),
-                   QName("foo::int32"), QName("foo::int32_t"), QName("foo::v1"),
-                   QName("foo::bar::v2"), QName("foo::baz")}));
+  EXPECT_THAT(
+      Symbols,
+      UnorderedElementsAreArray(
+          {QName("Foo"), QName("Foo::f"), QName("f1"), QName("f2"),
+           QName("KInt"), QName("kStr"), QName("foo"), QName("foo::bar"),
+           QName("foo::int32"), QName("foo::int32_t"), QName("foo::v1"),
+           QName("foo::bar::v2"), QName("foo::baz")}));
 }
 
 TEST_F(SymbolCollectorTest, Template) {
   Annotations Header(R"(
     // Template is indexed, specialization and instantiation is not.
-    template <class T> struct [[Tmpl]] {T x = 0;};
+    template <class T> struct [[Tmpl]] {T $xdecl[[x]] = 0;};
     template <> struct Tmpl<int> {};
     extern template struct Tmpl<float>;
     template struct Tmpl<double>;
   )");
   runSymbolCollector(Header.code(), /*Main=*/"");
-  EXPECT_THAT(Symbols, UnorderedElementsAreArray({AllOf(
-                           QName("Tmpl"), DeclRange(Header.range()))}));
+  EXPECT_THAT(Symbols,
+              UnorderedElementsAreArray(
+                  {AllOf(QName("Tmpl"), DeclRange(Header.range())),
+                   AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")))}));
 }
 
 TEST_F(SymbolCollectorTest, Locations) {
@@ -334,29 +340,30 @@
       Green
     };
     enum class Color2 {
-      Yellow // ignore
+      Yellow
     };
     namespace ns {
     enum {
       Black
     };
     }
   )";
   runSymbolCollector(Header, /*Main=*/"");
-  EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Red"), QName("Color"),
-                                            QName("Green"), QName("Color2"),
-                                            QName("ns"), QName("ns::Black")));
+  EXPECT_THAT(Symbols,
+              UnorderedElementsAre(QName("Red"), QName("Color"), QName("Green"),
+                                   QName("Color2"), QName("Color2::Yellow"),
+                                   QName("ns"), QName("ns::Black")));
 }
 
-TEST_F(SymbolCollectorTest, IgnoreNamelessSymbols) {
+TEST_F(SymbolCollectorTest, NamelessSymbols) {
   const std::string Header = R"(
     struct {
       int a;
     } Foo;
   )";
   runSymbolCollector(Header, /*Main=*/"");
-  EXPECT_THAT(Symbols,
-              UnorderedElementsAre(QName("Foo")));
+  EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"),
+                                            QName("(anonymous struct)::a")));
 }
 
 TEST_F(SymbolCollectorTest, SymbolFormedFromMacro) {
@@ -417,7 +424,7 @@
               UnorderedElementsAre(QName("Foo"), QName("f1"), QName("f2")));
 }
 
-TEST_F(SymbolCollectorTest, IgnoreClassMembers) {
+TEST_F(SymbolCollectorTest, ClassMembers) {
   const std::string Header = R"(
     class Foo {
       void f() {}
@@ -432,7 +439,10 @@
     void Foo::ssf() {}
   )";
   runSymbolCollector(Header, Main);
-  EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo")));
+  EXPECT_THAT(Symbols,
+              UnorderedElementsAre(QName("Foo"), QName("Foo::f"),
+                                   QName("Foo::g"), QName("Foo::sf"),
+                                   QName("Foo::ssf"), QName("Foo::x")));
 }
 
 TEST_F(SymbolCollectorTest, Scopes) {
@@ -531,6 +541,7 @@
   End:
     Line: 1
     Column: 1
+InScopedEnum:    true
 CompletionLabel:    'Foo1-label'
 CompletionFilterText:    'filter'
 CompletionPlainInsertText:    'plain'
@@ -555,6 +566,7 @@
   End:
     Line: 1
     Column: 1
+InScopedEnum:    false
 CompletionLabel:    'Foo2-label'
 CompletionFilterText:    'filter'
 CompletionPlainInsertText:    'plain'
@@ -565,13 +577,15 @@
   auto Symbols1 = SymbolsFromYAML(YAML1);
 
   EXPECT_THAT(Symbols1,
-              UnorderedElementsAre(AllOf(
-                  QName("clang::Foo1"), Labeled("Foo1-label"), Doc("Foo doc"),
-                  Detail("int"), DeclURI("file:///path/foo.h"))));
+              UnorderedElementsAre(
+                  AllOf(QName("clang::Foo1"), Labeled("Foo1-label"),
+                        Doc("Foo doc"), Detail("int"),
+                        DeclURI("file:///path/foo.h"), InScopedEnum(true))));
   auto Symbols2 = SymbolsFromYAML(YAML2);
-  EXPECT_THAT(Symbols2, UnorderedElementsAre(AllOf(
-                            QName("clang::Foo2"), Labeled("Foo2-label"),
-                            Not(HasDetail()), DeclURI("file:///path/bar.h"))));
+  EXPECT_THAT(Symbols2,
+              UnorderedElementsAre(AllOf(
+                  QName("clang::Foo2"), Labeled("Foo2-label"), Not(HasDetail()),
+                  DeclURI("file:///path/bar.h"), InScopedEnum(false))));
 
   std::string ConcatenatedYAML;
   {
@@ -662,23 +676,27 @@
     // Canonical declarations.
     class $cdecl[[C]] {};
     struct $sdecl[[S]] {};
-    union $udecl[[U]] {int x; bool y;};
+    union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
   )");
   runSymbolCollector(Header.code(), /*Main=*/"");
-  EXPECT_THAT(Symbols,
-              UnorderedElementsAre(
-                  AllOf(QName("C"), DeclURI(TestHeaderURI),
-                        DeclRange(Header.range("cdecl")),
-                        IncludeHeader(TestHeaderURI), DefURI(TestHeaderURI),
-                        DefRange(Header.range("cdecl"))),
-                  AllOf(QName("S"), DeclURI(TestHeaderURI),
-                        DeclRange(Header.range("sdecl")),
-                        IncludeHeader(TestHeaderURI), DefURI(TestHeaderURI),
-                        DefRange(Header.range("sdecl"))),
-                  AllOf(QName("U"), DeclURI(TestHeaderURI),
-                        DeclRange(Header.range("udecl")),
-                        IncludeHeader(TestHeaderURI), DefURI(TestHeaderURI),
-                        DefRange(Header.range("udecl")))));
+  EXPECT_THAT(
+      Symbols,
+      UnorderedElementsAre(
+          AllOf(QName("C"), DeclURI(TestHeaderURI),
+                DeclRange(Header.range("cdecl")), IncludeHeader(TestHeaderURI),
+                DefURI(TestHeaderURI), DefRange(Header.range("cdecl"))),
+          AllOf(QName("S"), DeclURI(TestHeaderURI),
+                DeclRange(Header.range("sdecl")), IncludeHeader(TestHeaderURI),
+                DefURI(TestHeaderURI), DefRange(Header.range("sdecl"))),
+          AllOf(QName("U"), DeclURI(TestHeaderURI),
+                DeclRange(Header.range("udecl")), IncludeHeader(TestHeaderURI),
+                DefURI(TestHeaderURI), DefRange(Header.range("udecl"))),
+          AllOf(QName("U::x"), DeclURI(TestHeaderURI),
+                DeclRange(Header.range("xdecl")), DefURI(TestHeaderURI),
+                DefRange(Header.range("xdecl"))),
+          AllOf(QName("U::y"), DeclURI(TestHeaderURI),
+                DeclRange(Header.range("ydecl")), DefURI(TestHeaderURI),
+                DefRange(Header.range("ydecl")))));
 }
 
 TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
Index: unittests/clangd/FindSymbolsTests.cpp
===================================================================
--- unittests/clangd/FindSymbolsTests.cpp
+++ unittests/clangd/FindSymbolsTests.cpp
@@ -120,7 +120,10 @@
   EXPECT_THAT(getSymbols("UnnamedStruct"),
               ElementsAre(AllOf(Named("UnnamedStruct"),
                                 WithKind(SymbolKind::Variable))));
-  EXPECT_THAT(getSymbols("InUnnamed"), IsEmpty());
+  EXPECT_THAT(
+      getSymbols("InUnnamed"),
+      ElementsAre(AllOf(Named("InUnnamed"), InContainer("(anonymous struct)"),
+                        WithKind(SymbolKind::Field))));
 }
 
 TEST_F(WorkspaceSymbolsTest, InMainFile) {
Index: unittests/clangd/FileIndexTests.cpp
===================================================================
--- unittests/clangd/FileIndexTests.cpp
+++ unittests/clangd/FileIndexTests.cpp
@@ -170,15 +170,16 @@
   EXPECT_THAT(match(M, FuzzyFindRequest()), UnorderedElementsAre());
 }
 
-TEST(FileIndexTest, IgnoreClassMembers) {
+TEST(FileIndexTest, ClassMembers) {
   FileIndex M;
   M.update("f1",
            build("f1", "class X { static int m1; int m2; static void f(); };")
                .getPointer());
 
   FuzzyFindRequest Req;
   Req.Query = "";
-  EXPECT_THAT(match(M, Req), UnorderedElementsAre("X"));
+  EXPECT_THAT(match(M, Req),
+              UnorderedElementsAre("X", "X::m1", "X::m2", "X::f"));
 }
 
 TEST(FileIndexTest, NoIncludeCollected) {
Index: unittests/clangd/CodeCompleteTests.cpp
===================================================================
--- unittests/clangd/CodeCompleteTests.cpp
+++ unittests/clangd/CodeCompleteTests.cpp
@@ -30,6 +30,7 @@
 using ::testing::Each;
 using ::testing::ElementsAre;
 using ::testing::Field;
+using ::testing::IsEmpty;
 using ::testing::Not;
 using ::testing::UnorderedElementsAre;
 
@@ -115,7 +116,8 @@
 
 // Helpers to produce fake index symbols for memIndex() or completions().
 // USRFormat is a regex replacement string for the unqualified part of the USR.
-Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
+Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat,
+           Decl::Kind ContextKind) {
   Symbol Sym;
   std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
   size_t Pos = QName.rfind("::");
@@ -133,19 +135,27 @@
   Sym.CompletionSnippetInsertText = Sym.Name;
   Sym.CompletionLabel = Sym.Name;
   Sym.SymInfo.Kind = Kind;
+  Sym.DeclContextKind = ContextKind;
   return Sym;
 }
-Symbol func(StringRef Name) { // Assumes the function has no args.
-  return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
+Symbol
+func(StringRef Name,
+     Decl::Kind ContextKind =
+         Decl::Kind::TranslationUnit) { // Assumes the function has no args.
+  return sym(Name, index::SymbolKind::Function, "@F@\\0#",
+             ContextKind); // no args
 }
-Symbol cls(StringRef Name) {
-  return sym(Name, index::SymbolKind::Class, "@S@\\0@S@\\0");
+Symbol cls(StringRef Name,
+           Decl::Kind ContextKind = Decl::Kind::TranslationUnit) {
+  return sym(Name, index::SymbolKind::Class, "@S@\\0@S@\\0", ContextKind);
 }
-Symbol var(StringRef Name) {
-  return sym(Name, index::SymbolKind::Variable, "@\\0");
+Symbol var(StringRef Name,
+           Decl::Kind ContextKind = Decl::Kind::TranslationUnit) {
+  return sym(Name, index::SymbolKind::Variable, "@\\0", ContextKind);
 }
-Symbol ns(StringRef Name) {
-  return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
+Symbol ns(StringRef Name,
+          Decl::Kind ContextKind = Decl::Kind::TranslationUnit) {
+  return sym(Name, index::SymbolKind::Namespace, "@N@\\0", ContextKind);
 }
 Symbol withReferences(int N, Symbol S) {
   S.References = N;
@@ -436,16 +446,17 @@
           namespace fake { int Babble, Ball; };
           int main() { fake::bb^ }
       ")cpp",
-      {var("fake::BigBang")});
+      {var("fake::BigBang", Decl::Kind::Namespace)});
   EXPECT_THAT(Results.items, ElementsAre(Named("BigBang"), Named("Babble")));
 }
 
 TEST(CompletionTest, ScopedWithFilter) {
   auto Results = completions(
       R"cpp(
           void f() { ns::x^ }
       )cpp",
-      {cls("ns::XYZ"), func("ns::foo")});
+      {cls("ns::XYZ", Decl::Kind::Namespace),
+       func("ns::foo", Decl::Kind::Namespace)});
   EXPECT_THAT(Results.items,
               UnorderedElementsAre(AllOf(Named("XYZ"), Filter("XYZ"))));
 }
@@ -474,7 +485,7 @@
           namespace ns { void bar(); }
           void f() { ::ns::^ }
       )cpp",
-      {cls("ns::XYZ")});
+      {cls("ns::XYZ", Decl::Kind::Namespace)});
   EXPECT_THAT(Results.items, AllOf(Has("XYZ", CompletionItemKind::Class),
                                    Has("bar", CompletionItemKind::Function)));
 }
@@ -485,7 +496,8 @@
           namespace ns { int local; void both(); }
           void f() { ::ns::^ }
       )cpp",
-      {func("ns::both"), cls("ns::Index")});
+      {func("ns::both", Decl::Kind::Namespace),
+       cls("ns::Index", Decl::Kind::Namespace)});
   // We get results from both index and sema, with no duplicates.
   EXPECT_THAT(
       Results.items,
@@ -500,7 +512,9 @@
           namespace ns { int local; void both(); }
           void f() { ::ns::^ }
       )cpp",
-      {func("ns::both"), cls("ns::Index")}, Opts);
+      {func("ns::both", Decl::Kind::Namespace),
+       cls("ns::Index", Decl::Kind::Namespace)},
+      Opts);
   EXPECT_EQ(Results.items.size(), Opts.Limit);
   EXPECT_TRUE(Results.isIncomplete);
 }
@@ -523,7 +537,7 @@
   runAddDocument(Server, File, Test.code());
   clangd::CodeCompleteOptions Opts = {};
 
-  auto I = memIndex({var("ns::index")});
+  auto I = memIndex({var("ns::index", Decl::Kind::Namespace)});
   Opts.Index = I.get();
   auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
   EXPECT_THAT(WithIndex.items,
@@ -576,6 +590,33 @@
                                             Doc("Doooc"), Detail("void"))));
 }
 
+TEST(CompletionTest, DynamicIndexMultiFileMembers) {
+  MockFSProvider FS;
+  MockCompilationDatabase CDB;
+  IgnoreDiagnostics DiagConsumer;
+  auto Opts = ClangdServer::optsForTest();
+  Opts.BuildDynamicSymbolIndex = true;
+  ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+
+  FS.Files[testPath("foo.h")] = R"cpp(
+      struct XYZ {void fooooo() {} };
+  )cpp";
+  runAddDocument(Server, testPath("foo.cpp"), R"cpp(
+      #include "foo.h"
+  )cpp");
+
+  auto File = testPath("bar.cpp");
+  Annotations Test(R"cpp(
+      void f() {
+      XYZ::foooo^
+      }
+  )cpp");
+  runAddDocument(Server, File, Test.code());
+
+  auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
+  EXPECT_THAT(Results.items, IsEmpty());
+}
+
 TEST(CodeCompleteTest, DisableTypoCorrection) {
   auto Results = completions(R"cpp(
      namespace clang { int v; }
@@ -633,6 +674,142 @@
   EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
 }
 
+TEST(CompletionTest, Enums) {
+  EXPECT_THAT(completions(R"cpp(
+        enum class Color2 {
+          Yellow
+        };
+        void foo() {
+          Color2::^
+        })cpp")
+                  .items,
+              Has("Yellow", CompletionItemKind::Value));
+  EXPECT_THAT(completions(R"cpp(
+        enum {
+          Red
+        };
+        void foo() {
+          Re^
+        })cpp")
+                  .items,
+              Has("Red", CompletionItemKind::Value));
+  EXPECT_THAT(completions(R"cpp(
+      enum Color {
+        Green
+      };
+      void foo() {
+        Gr^
+      })cpp")
+                  .items,
+              Has("Green", CompletionItemKind::Value));
+  EXPECT_THAT(completions(R"cpp(
+        namespace ns {
+        enum {
+          Black
+        };
+        }
+        void foo() {
+          ns::B^
+        })cpp")
+                  .items,
+              Has("Black", CompletionItemKind::Value));
+  EXPECT_THAT(completions(R"cpp(
+        void foo() {
+          ns::B^
+        })cpp")
+                  .items,
+              IsEmpty());
+
+  MockFSProvider FS;
+  MockCompilationDatabase CDB;
+  CDB.ExtraClangFlags.push_back("-std=c++11");
+  IgnoreDiagnostics DiagConsumer;
+  auto Opts = ClangdServer::optsForTest();
+  Opts.BuildDynamicSymbolIndex = true;
+  ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+  auto Code = R"(
+      enum class Color {
+        Yellow
+      };
+  )";
+
+  auto File = testPath("foo.h");
+  Server.addDocument(File, Code);
+  FS.Files[File] = Code;
+
+  Server.addDocument(testPath("bar.cpp"), R"(
+      #include "foo.h"
+  )");
+
+  File = testPath("bar2.cpp");
+  Annotations Test(R"(
+      void foo() {
+        Color::Y^
+      }
+  )");
+  Server.addDocument(File, Test.code());
+
+  ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
+  auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
+  EXPECT_THAT(Results.items, IsEmpty());
+}
+
+TEST(CompletionTest, AnonymousNamespace) {
+
+  MockFSProvider FS;
+  MockCompilationDatabase CDB;
+  IgnoreDiagnostics DiagConsumer;
+  auto Opts = ClangdServer::optsForTest();
+  Opts.BuildDynamicSymbolIndex = true;
+  ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+  auto File = testPath("bar.cpp");
+  Server.addDocument(File, R"(
+      namespace {
+      void inAnymous() {
+      }
+      } // namespace
+    )");
+
+  File = testPath("bar2.cpp");
+  Annotations Test(R"(
+      void bar() {
+        inAnym^
+      }
+  )");
+
+  Server.addDocument(File, Test.code());
+  ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
+  auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
+  EXPECT_THAT(Results.items, IsEmpty());
+}
+
+TEST(CompletionTest, InMainFile) {
+
+  MockFSProvider FS;
+  MockCompilationDatabase CDB;
+  IgnoreDiagnostics DiagConsumer;
+  auto Opts = ClangdServer::optsForTest();
+  Opts.BuildDynamicSymbolIndex = true;
+  ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+  auto File = testPath("main.cpp");
+  Server.addDocument(File, R"(
+      void funcInMain() {
+      }
+    )");
+
+  File = testPath("bar.cpp");
+  Annotations Test(R"(
+      void bar() {
+        funcInMa^
+      }
+  )");
+
+  Server.addDocument(File, Test.code());
+  ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
+  auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
+  EXPECT_THAT(Results.items, IsEmpty());
+}
+
 SignatureHelp signatures(StringRef Text) {
   MockFSProvider FS;
   MockCompilationDatabase CDB;
Index: clangd/index/SymbolYAML.cpp
===================================================================
--- clangd/index/SymbolYAML.cpp
+++ clangd/index/SymbolYAML.cpp
@@ -9,6 +9,7 @@
 
 #include "SymbolYAML.h"
 #include "Index.h"
+#include "clang/AST/DeclBase.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -95,6 +96,26 @@
   llvm::Optional<T> Opt;
 };
 
+template <> struct ScalarTraits<clang::Decl::Kind> {
+  static void output(const clang::Decl::Kind &Value, void *Ctx,
+                     raw_ostream &OS) {
+    return ScalarTraits<unsigned>::output(static_cast<unsigned>(Value), Ctx,
+                                          OS);
+  }
+
+  static StringRef input(StringRef Scalar, void *Ctx,
+                         clang::Decl::Kind &Value) {
+    unsigned Val;
+    auto Err = ScalarTraits<unsigned>::input(Scalar, Ctx, Val);
+    Value = static_cast<clang::Decl::Kind>(Val);
+    return Err;
+  }
+
+  static QuotingType mustQuote(StringRef Scalar) {
+    return ScalarTraits<unsigned>::mustQuote(Scalar);
+  }
+};
+
 template <> struct MappingTraits<Symbol> {
   static void mapping(IO &IO, Symbol &Sym) {
     MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID);
@@ -108,6 +129,9 @@
                    SymbolLocation());
     IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
     IO.mapOptional("References", Sym.References, 0u);
+    IO.mapOptional("InScopedEnum", Sym.InScopedEnum, false);
+    IO.mapOptional("DeclContextKind", Sym.DeclContextKind,
+                   static_cast<clang::Decl::Kind>(0));
     IO.mapRequired("CompletionLabel", Sym.CompletionLabel);
     IO.mapRequired("CompletionFilterText", Sym.CompletionFilterText);
     IO.mapRequired("CompletionPlainInsertText", Sym.CompletionPlainInsertText);
Index: clangd/index/SymbolCollector.cpp
===================================================================
--- clangd/index/SymbolCollector.cpp
+++ clangd/index/SymbolCollector.cpp
@@ -110,21 +110,12 @@
   if (ND->isInAnonymousNamespace())
     return true;
 
-  // We only want:
-  //   * symbols in namespaces or translation unit scopes (e.g. no class
-  //     members)
-  //   * enum constants in unscoped enum decl (e.g. "red" in "enum {red};")
-  auto InTopLevelScope = hasDeclContext(
-      anyOf(namespaceDecl(), translationUnitDecl(), linkageSpecDecl()));
-  // Don't index template specializations.
+  // Don't index template specializations and expansions in main files.
   auto IsSpecialization =
       anyOf(functionDecl(isExplicitTemplateSpecialization()),
             cxxRecordDecl(isExplicitTemplateSpecialization()),
             varDecl(isExplicitTemplateSpecialization()));
   if (match(decl(allOf(unless(isExpansionInMainFile()),
-                       anyOf(InTopLevelScope,
-                             hasDeclContext(enumDecl(InTopLevelScope,
-                                                     unless(isScoped())))),
                        unless(IsSpecialization))),
             *ND, *ASTCtx)
           .empty())
@@ -319,6 +310,11 @@
           getSymbolLocation(ND, SM, Opts, ASTCtx->getLangOpts(), FileURI))
     S.CanonicalDeclaration = *DeclLoc;
 
+  using namespace clang::ast_matchers;
+  S.DeclContextKind = ND.getDeclContext()->getDeclKind();
+  S.InScopedEnum =
+      !match(decl(hasDeclContext(enumDecl(isScoped()))), ND, *ASTCtx).empty();
+
   // Add completion info.
   // FIXME: we may want to choose a different redecl, or combine from several.
   assert(ASTCtx && PP.get() && "ASTContext and Preprocessor must be set.");
Index: clangd/index/MemIndex.cpp
===================================================================
--- clangd/index/MemIndex.cpp
+++ clangd/index/MemIndex.cpp
@@ -10,6 +10,7 @@
 #include "MemIndex.h"
 #include "../FuzzyMatch.h"
 #include "../Logger.h"
+#include <bitset>
 #include <queue>
 
 namespace clang {
@@ -34,6 +35,10 @@
   assert(!StringRef(Req.Query).contains("::") &&
          "There must be no :: in query.");
 
+  std::bitset<Decl::Kind::lastDecl + 1> ContextFilter;
+  for (Decl::Kind Kind : Req.DeclContexts)
+    ContextFilter.set(static_cast<size_t>(Kind));
+
   std::priority_queue<std::pair<float, const Symbol *>> Top;
   FuzzyMatcher Filter(Req.Query);
   bool More = false;
@@ -45,6 +50,11 @@
       // Exact match against all possible scopes.
       if (!Req.Scopes.empty() && !llvm::is_contained(Req.Scopes, Sym->Scope))
         continue;
+      if (!Req.DeclContexts.empty() &&
+          !ContextFilter.test(Sym->DeclContextKind))
+        continue;
+      if (!Req.IncludeInScopedEnum && Sym->InScopedEnum)
+        continue;
 
       if (auto Score = Filter.match(Sym->Name)) {
         Top.emplace(-*Score * quality(*Sym), Sym);
Index: clangd/index/Index.h
===================================================================
--- clangd/index/Index.h
+++ clangd/index/Index.h
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
 
+#include "clang/AST/DeclBase.h"
 #include "clang/Index/IndexSymbol.h"
 #include "clang/Lex/Lexer.h"
 #include "llvm/ADT/DenseMap.h"
@@ -155,9 +156,12 @@
   // The number of translation units that reference this symbol from their main
   // file. This number is only meaningful if aggregated in an index.
   unsigned References = 0;
-
+  /// The Decl::Kind for the context of the symbol, i.e. what contains it.
+  Decl::Kind DeclContextKind;
+  /// Whether or not this is an enumerator inside a scoped enum (C++11).
+  bool InScopedEnum = false;
   /// A brief description of the symbol that can be displayed in the completion
-  /// candidate list. For example, "Foo(X x, Y y) const" is a labal for a
+  /// candidate list. For example, "Foo(X x, Y y) const" is a label for a
   /// function.
   llvm::StringRef CompletionLabel;
   /// The piece of text that the user is expected to type to match the
@@ -273,6 +277,11 @@
   /// \brief The number of top candidates to return. The index may choose to
   /// return more than this, e.g. if it doesn't know which candidates are best.
   size_t MaxCandidateCount = UINT_MAX;
+  // If set to false, enumerators inside scoped Enums will be skipped.
+  bool IncludeInScopedEnum = true;
+  /// Filter results to only those in specified contexts. If empty all context
+  /// are considered.
+  std::vector<Decl::Kind> DeclContexts;
 };
 
 struct LookupRequest {
Index: clangd/CodeComplete.cpp
===================================================================
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -929,6 +929,9 @@
     if (Opts.Limit)
       Req.MaxCandidateCount = Opts.Limit;
     Req.Query = Filter->pattern();
+    Req.DeclContexts = {Decl::Kind::Namespace, Decl::Kind::TranslationUnit,
+                        Decl::Kind::LinkageSpec, Decl::Kind::Enum};
+    Req.IncludeInScopedEnum = false;
     Req.Scopes = getQueryScopes(Recorder->CCContext,
                                 Recorder->CCSema->getSourceManager());
     log(llvm::formatv("Code complete: fuzzyFind(\"{0}\", scopes=[{1}])",
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to