malaperle updated this revision to Diff 148329.
malaperle added a comment.

Use "SupportGlobalCompletion", white-list decl contexts, add more tests


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(SupportGlobalCompletion, SupportGlobalCompletion, "") {
+  return arg.SupportGlobalCompletion == SupportGlobalCompletion;
+}
 
 namespace clang {
 namespace clangd {
@@ -163,8 +166,20 @@
 TEST_F(SymbolCollectorTest, CollectSymbols) {
   const std::string Header = R"(
     class Foo {
+      Foo() {}
+      Foo(int a) {}
+      void f();
+      friend void f1();
+      friend class Friend;
+      Foo& operator=(const Foo&);
+      ~Foo();
+      class Nested {
       void f();
+      };
     };
+    class Friend {
+    };
+
     void f1();
     inline void f2() {}
     static const int KInt = 2;
@@ -198,25 +213,68 @@
     } // 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::Foo"),
+                            QName("Foo::Foo"),     QName("Foo::f"),
+                            QName("Foo::~Foo"),    QName("Foo::operator="),
+                            QName("Foo::Nested"),  QName("Foo::Nested::f"),
+                            QName("Friend"),       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, ObjCSymbols) {
+  const std::string Header = R"(
+    @interface Person
+    - (void)someMethodName:(void*)name1 lastName:(void*)lName;
+    @end
+
+    @implementation Person
+    - (void)someMethodName:(void*)name1 lastName:(void*)lName{
+      int foo;
+      ^(int param){ int bar; };
+    }
+    @end
+
+    @interface Person (MyCategory)
+    - (void)someMethodName2:(void*)name2;
+    @end
+
+    @implementation Person (MyCategory)
+    - (void)someMethodName2:(void*)name2 {
+      int foo2;
+    }
+    @end
+
+    @protocol MyProtocol
+    - (void)someMethodName3:(void*)name3;
+    @end
+  )";
+  TestFileName = "test.m";
+  runSymbolCollector(Header, /*Main=*/"", {"-fblocks"});
+  EXPECT_THAT(Symbols,
+              UnorderedElementsAre(
+                  QName("Person"), QName("Person::someMethodName:lastName:"),
+                  QName("MyCategory"), QName("Person::someMethodName2:"),
+                  QName("MyProtocol"), QName("MyProtocol::someMethodName3:")));
 }
 
 TEST_F(SymbolCollectorTest, Locations) {
@@ -334,29 +392,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 +476,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 +491,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 +593,7 @@
   End:
     Line: 1
     Column: 1
+SupportGlobalCompletion:    true
 CompletionLabel:    'Foo1-label'
 CompletionFilterText:    'filter'
 CompletionPlainInsertText:    'plain'
@@ -555,6 +618,7 @@
   End:
     Line: 1
     Column: 1
+SupportGlobalCompletion:    false
 CompletionLabel:    'Foo2-label'
 CompletionFilterText:    'filter'
 CompletionPlainInsertText:    'plain'
@@ -567,11 +631,13 @@
   EXPECT_THAT(Symbols1,
               UnorderedElementsAre(AllOf(
                   QName("clang::Foo1"), Labeled("Foo1-label"), Doc("Foo doc"),
-                  Detail("int"), DeclURI("file:///path/foo.h"))));
+                  Detail("int"), DeclURI("file:///path/foo.h"),
+                  SupportGlobalCompletion(true))));
   auto Symbols2 = SymbolsFromYAML(YAML2);
   EXPECT_THAT(Symbols2, UnorderedElementsAre(AllOf(
                             QName("clang::Foo2"), Labeled("Foo2-label"),
-                            Not(HasDetail()), DeclURI("file:///path/bar.h"))));
+                            Not(HasDetail()), DeclURI("file:///path/bar.h"),
+                            SupportGlobalCompletion(false))));
 
   std::string ConcatenatedYAML;
   {
@@ -677,23 +743,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) {
@@ -223,6 +226,44 @@
   EXPECT_THAT(getSymbols(""), IsEmpty());
 }
 
+TEST_F(WorkspaceSymbolsTest, Enums) {
+  addFile("foo.h", R"cpp(
+    enum {
+      Red
+    };
+    enum Color {
+      Green
+    };
+    enum class Color2 {
+      Yellow
+    };
+    namespace ns {
+      enum {
+        Black
+      };
+      enum Color3 {
+        Blue
+      };
+      enum class Color4 {
+        White
+      };
+    }
+      )cpp");
+  addFile("foo.cpp", R"cpp(
+      #include "foo.h"
+      )cpp");
+  EXPECT_THAT(getSymbols("Red"), ElementsAre(Named("Red")));
+  EXPECT_THAT(getSymbols("::Red"), ElementsAre(Named("Red")));
+  EXPECT_THAT(getSymbols("Green"), ElementsAre(Named("Green")));
+  EXPECT_THAT(getSymbols("Green"), ElementsAre(Named("Green")));
+  EXPECT_THAT(getSymbols("Color2::Yellow"), ElementsAre(Named("Yellow")));
+  EXPECT_THAT(getSymbols("Yellow"), ElementsAre(Named("Yellow")));
+
+  EXPECT_THAT(getSymbols("ns::Black"), ElementsAre(Named("Black")));
+  EXPECT_THAT(getSymbols("ns::Blue"), ElementsAre(Named("Blue")));
+  EXPECT_THAT(getSymbols("ns::Color4::White"), ElementsAre(Named("White")));
+}
+
 TEST_F(WorkspaceSymbolsTest, WithLimit) {
   addFile("foo.h", R"cpp(
       int foo;
Index: unittests/clangd/FileIndexTests.cpp
===================================================================
--- unittests/clangd/FileIndexTests.cpp
+++ unittests/clangd/FileIndexTests.cpp
@@ -139,13 +139,14 @@
   EXPECT_THAT(match(M, FuzzyFindRequest()), UnorderedElementsAre());
 }
 
-TEST(FileIndexTest, IgnoreClassMembers) {
+TEST(FileIndexTest, ClassMembers) {
   FileIndex M;
   update(M, "f1", "class X { static int m1; int m2; static void f(); };");
 
   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;
 
@@ -151,6 +152,7 @@
   Sym.CompletionSnippetInsertText = Sym.Name;
   Sym.CompletionLabel = Sym.Name;
   Sym.SymInfo.Kind = Kind;
+  Sym.SupportGlobalCompletion = true;
   return Sym;
 }
 Symbol func(StringRef Name) { // Assumes the function has no args.
@@ -652,6 +654,33 @@
               Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
 }
 
+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; }
@@ -709,6 +738,141 @@
   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;
+  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
@@ -108,6 +108,8 @@
                    SymbolLocation());
     IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
     IO.mapOptional("References", Sym.References, 0u);
+    IO.mapOptional("SupportGlobalCompletion", Sym.SupportGlobalCompletion,
+                   false);
     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
@@ -149,21 +149,20 @@
   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.
+  // We want most things but not "local" symbols such as symbols inside
+  // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl.
+  // FIXME: Need a matcher for ExportDecl in order to include symbols declared
+  // within an export.
+  auto InNonLocalContext = hasDeclContext(anyOf(
+      translationUnitDecl(), namespaceDecl(), linkageSpecDecl(), recordDecl(),
+      enumDecl(), objcProtocolDecl(), objcInterfaceDecl(), objcCategoryDecl(),
+      objcCategoryImplDecl(), objcImplementationDecl()));
+  // 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())))),
+  if (match(decl(allOf(unless(isExpansionInMainFile()), InNonLocalContext,
                        unless(IsSpecialization))),
             *ND, *ASTCtx)
           .empty())
@@ -356,6 +355,25 @@
   Symbol S;
   S.ID = std::move(ID);
   std::tie(S.Scope, S.Name) = splitQualifiedName(QName);
+
+  // For global completion, 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};")
+  // For the other cases, we let Clang do the completion because it does not
+  // need any non-local information and it will be much better at following
+  // lookup rules.
+  using namespace clang::ast_matchers;
+  auto InTopLevelScope = hasDeclContext(
+      anyOf(namespaceDecl(), translationUnitDecl(), linkageSpecDecl()));
+  // Don't index template specializations.
+  S.SupportGlobalCompletion =
+      !match(decl(anyOf(InTopLevelScope,
+                        hasDeclContext(
+                            enumDecl(InTopLevelScope, unless(isScoped()))))),
+             ND, *ASTCtx)
+           .empty();
+
   S.SymInfo = index::getSymbolInfo(&ND);
   std::string FileURI;
   if (auto DeclLoc =
Index: clangd/index/MemIndex.cpp
===================================================================
--- clangd/index/MemIndex.cpp
+++ clangd/index/MemIndex.cpp
@@ -45,6 +45,8 @@
       // Exact match against all possible scopes.
       if (!Req.Scopes.empty() && !llvm::is_contained(Req.Scopes, Sym->Scope))
         continue;
+      if (Req.GlobalCodeCompletionOnly && !Sym->SupportGlobalCompletion)
+        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
@@ -155,9 +155,11 @@
   // 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;
-
+  /// Whether or not this is symbol is meant to be used for the global
+  /// completion.
+  bool SupportGlobalCompletion = 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 +275,9 @@
   /// \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 true, only symbols with global completion support will be
+  /// considered.
+  bool GlobalCodeCompletionOnly = false;
 };
 
 struct LookupRequest {
Index: clangd/CodeComplete.cpp
===================================================================
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -927,6 +927,7 @@
     if (Opts.Limit)
       Req.MaxCandidateCount = Opts.Limit;
     Req.Query = Filter->pattern();
+    Req.GlobalCodeCompletionOnly = true;
     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