hokein created this revision.
hokein added a reviewer: ilya-biryukov.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay, ioeric.

We are missing docs for class member completion -- we don't store
comments in the preamble, so Sema doesn't return any docs. To get docs
for class members, we rely on the index (mostly dynamic index).

Tried it on llvm, didn't get noticeble delay for the completion.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D56492

Files:
  clangd/CodeComplete.cpp
  unittests/clangd/CodeCompleteTests.cpp

Index: unittests/clangd/CodeCompleteTests.cpp
===================================================================
--- unittests/clangd/CodeCompleteTests.cpp
+++ unittests/clangd/CodeCompleteTests.cpp
@@ -729,6 +729,62 @@
                         Doc("Doooc"), ReturnType("void"))));
 }
 
+TEST(CompletionTest, DocumentationFromIndex) {
+  MockFSProvider FS;
+  MockCompilationDatabase CDB;
+  IgnoreDiagnostics DiagConsumer;
+  FS.Files[testPath("foo.h")] = R"cpp(
+      class Foo {
+      public:
+        // Doc for foo
+        int foo();
+
+        // Doc for foo int
+        int foo2(int);
+        // Doc for foo bool
+        int foo2(bool);
+      };
+  )cpp";
+
+  auto File = testPath("bar.cpp");
+  Annotations Test(R"cpp(
+      #include "foo.h"
+      void test() {
+        Foo f;
+        f.^
+      }
+  )cpp");
+  auto Opts = ClangdServer::optsForTest();
+  {
+    Opts.BuildDynamicSymbolIndex = false;
+    ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+    runAddDocument(Server, File, Test.code());
+    auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
+    EXPECT_THAT(
+        Results.Completions,
+        Contains((Named("foo"), Kind(CompletionItemKind::Method), Doc(""))));
+    EXPECT_THAT(
+        Results.Completions,
+        Contains((Named("foo2"), Kind(CompletionItemKind::Method), Doc(""))));
+  }
+  {
+    Opts.BuildDynamicSymbolIndex = true;
+    ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+    runAddDocument(Server, File, Test.code());
+    clangd::CodeCompleteOptions CCOpts;
+    CCOpts.BundleOverloads = true;
+    auto Results =
+        cantFail(runCodeComplete(Server, File, Test.point(), CCOpts));
+    EXPECT_THAT(Results.Completions,
+                Contains((Named("foo"), Kind(CompletionItemKind::Method),
+                          Doc("Doc for foo"))));
+    // No doc for overload bundle.
+    EXPECT_THAT(
+        Results.Completions,
+        Contains((Named("foo2"), Kind(CompletionItemKind::Method), Doc(""))));
+  }
+}
+
 TEST(CompletionTest, Documentation) {
   auto Results = completions(
       R"cpp(
Index: clangd/CodeComplete.cpp
===================================================================
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -1366,11 +1366,45 @@
     auto Top = mergeResults(Recorder->Results, IndexResults);
     CodeCompleteResult Output;
 
+    // Keys are indices into Output vector.
+    llvm::DenseMap<size_t, SymbolID> OutputIndex;
+    LookupRequest DocIndexRequest;
     // Convert the results to final form, assembling the expensive strings.
-    for (auto &C : Top) {
-      Output.Completions.push_back(toCodeCompletion(C.first));
-      Output.Completions.back().Score = C.second;
+    for (size_t i = 0; i < Top.size(); ++i) {
+      const ScoredBundle &BundleAndScope = Top[i];
+      const CompletionCandidate::Bundle &CandidateBundle = BundleAndScope.first;
+      Output.Completions.push_back(toCodeCompletion(CandidateBundle));
+      Output.Completions.back().Score = BundleAndScope.second;
       Output.Completions.back().CompletionTokenRange = TextEditRange;
+
+      if (Opts.IncludeComments &&
+          Output.Completions.back().Documentation.empty()) {
+        if (CandidateBundle.size() == 1) {
+          if (const CodeCompletionResult *SemaR =
+                  CandidateBundle.front().SemaResult) {
+            if (auto ID =
+                    getSymbolID(*SemaR, Recorder->CCSema->getSourceManager())) {
+              OutputIndex[i] = *ID;
+              DocIndexRequest.IDs.insert(*ID);
+            }
+          }
+        }
+      }
+    }
+    // Sema doesn't load docs from the preamble, so we get the docs from the
+    // index and assemble them for the final results.
+    if (!DocIndexRequest.IDs.empty() && Opts.Index) {
+      llvm::DenseMap<SymbolID, std::string> FetchedDocs;
+      Opts.Index->lookup(DocIndexRequest, [&](const Symbol &S) {
+        if (!S.Documentation.empty())
+          FetchedDocs[S.ID] = S.Documentation;
+      });
+      for (auto IndexAndID : OutputIndex) {
+        auto FetchDocsIt = FetchedDocs.find(IndexAndID.second);
+        if (FetchDocsIt != FetchedDocs.end())
+          Output.Completions[IndexAndID.first].Documentation =
+              FetchDocsIt->second;
+      }
     }
     Output.HasMore = Incomplete;
     Output.Context = Recorder->CCContext.getKind();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to