hokein created this revision.
hokein added reviewers: sammccall, ioeric.
Herald added subscribers: ilya-biryukov, klimek.

Use the YAML-format symbols (generated by the global-symbol-builder tool) to
do the global code completion.
It is **experimental** only , but it allows us to experience global code
completion on a relatively small project.

Tested with LLVM project.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D41668

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdLSPServer.h
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/CodeComplete.cpp
  clangd/CodeComplete.h
  clangd/index/MemIndex.cpp
  clangd/index/MemIndex.h
  clangd/tool/ClangdMain.cpp
  unittests/clangd/CodeCompleteTests.cpp

Index: unittests/clangd/CodeCompleteTests.cpp
===================================================================
--- unittests/clangd/CodeCompleteTests.cpp
+++ unittests/clangd/CodeCompleteTests.cpp
@@ -453,12 +453,6 @@
 
 std::unique_ptr<SymbolIndex> simpleIndexFromSymbols(
     std::vector<std::pair<std::string, index::SymbolKind>> Symbols) {
-  auto I = llvm::make_unique<MemIndex>();
-  struct Snapshot {
-    SymbolSlab Slab;
-    std::vector<const Symbol *> Pointers;
-  };
-  auto Snap = std::make_shared<Snapshot>();
   SymbolSlab::Builder Slab;
   for (const auto &Pair : Symbols) {
     Symbol Sym;
@@ -475,13 +469,7 @@
     Sym.SymInfo.Kind = Pair.second;
     Slab.insert(Sym);
   }
-  Snap->Slab = std::move(Slab).build();
-  for (auto &Iter : Snap->Slab)
-    Snap->Pointers.push_back(&Iter);
-  auto S = std::shared_ptr<std::vector<const Symbol *>>(std::move(Snap),
-                                                        &Snap->Pointers);
-  I->build(std::move(S));
-  return std::move(I);
+  return BuildMemIndex(std::move(Slab));
 }
 
 TEST(CompletionTest, NoIndex) {
@@ -496,6 +484,18 @@
   EXPECT_THAT(Results.items, Has("No"));
 }
 
+TEST(CompletionTest, StaticIndex) {
+  clangd::CodeCompleteOptions Opts;
+  auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
+  Opts.StaticIndex = I.get();
+
+  auto Results = completions(R"cpp(
+      void f() { ::ns::^ }
+  )cpp",
+                             Opts);
+  EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
+}
+
 TEST(CompletionTest, SimpleIndexBased) {
   clangd::CodeCompleteOptions Opts;
   auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -11,6 +11,7 @@
 #include "JSONRPCDispatcher.h"
 #include "Path.h"
 #include "Trace.h"
+#include "index/SymbolYAML.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
@@ -26,7 +27,25 @@
 
 namespace {
 enum class PCHStorageFlag { Disk, Memory };
+
+// Build an in-memory static index for global symbols from a YAML-format file.
+// The size of global symbols should be relatively small, so that all symbols
+// can be managed in memory.
+std::unique_ptr<SymbolIndex>
+BuildGlobalIndex(llvm::StringRef GlobalSymbolFilePath) {
+  auto Buffer = llvm::MemoryBuffer::getFile(GlobalSymbolFilePath);
+  if (!Buffer) {
+    llvm::errs() << "Can't open " << GlobalSymbolFilePath << "\n";
+    return nullptr;
+  }
+  auto Slab = SymbolFromYAML(Buffer.get()->getBuffer());
+  SymbolSlab::Builder SymsBuilder;
+  for (auto Sym : Slab)
+    SymsBuilder.insert(Sym);
+
+  return BuildMemIndex(std::move(SymsBuilder));
 }
+} // namespace
 
 static llvm::cl::opt<Path> CompileCommandsDir(
     "compile-commands-dir",
@@ -97,6 +116,13 @@
         "use index built from symbols in opened files"),
     llvm::cl::init(false), llvm::cl::Hidden);
 
+static llvm::cl::opt<Path> GlobalIndexFile(
+    "global-index-file",
+    llvm::cl::desc(
+        "YAML-format global symbol file to build the static index. It is only "
+        "available when 'enable-index-based-completion' is enabled."),
+    llvm::cl::init(""), llvm::cl::Hidden);
+
 int main(int argc, char *argv[]) {
   llvm::cl::ParseCommandLineOptions(argc, argv, "clangd");
 
@@ -182,13 +208,16 @@
   // Change stdin to binary to not lose \r\n on windows.
   llvm::sys::ChangeStdinToBinary();
 
+  std::unique_ptr<SymbolIndex> GlobalIdx;
+  if (EnableIndexBasedCompletion && !GlobalIndexFile.empty())
+    GlobalIdx = BuildGlobalIndex(GlobalIndexFile);
   clangd::CodeCompleteOptions CCOpts;
   CCOpts.EnableSnippets = EnableSnippets;
   CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
   // Initialize and run ClangdLSPServer.
   ClangdLSPServer LSPServer(Out, WorkerThreadsCount, StorePreamblesInMemory,
                             CCOpts, ResourceDirRef, CompileCommandsDirPath,
-                            EnableIndexBasedCompletion);
+                            EnableIndexBasedCompletion, std::move(GlobalIdx));
   constexpr int NoShutdownRequestErrorCode = 1;
   llvm::set_thread_name("clangd.main");
   return LSPServer.run(std::cin) ? 0 : NoShutdownRequestErrorCode;
Index: clangd/index/MemIndex.h
===================================================================
--- clangd/index/MemIndex.h
+++ clangd/index/MemIndex.h
@@ -36,6 +36,8 @@
   mutable std::mutex Mutex;
 };
 
+std::unique_ptr<SymbolIndex> BuildMemIndex(SymbolSlab::Builder Slab);
+
 } // namespace clangd
 } // namespace clang
 
Index: clangd/index/MemIndex.cpp
===================================================================
--- clangd/index/MemIndex.cpp
+++ clangd/index/MemIndex.cpp
@@ -53,5 +53,21 @@
   return true;
 }
 
+std::unique_ptr<SymbolIndex> BuildMemIndex(SymbolSlab::Builder Slab) {
+  struct Snapshot {
+    SymbolSlab Slab;
+    std::vector<const Symbol *> Pointers;
+  };
+  auto Snap = std::make_shared<Snapshot>();
+  Snap->Slab = std::move(Slab).build();
+  for (auto &Sym : Snap->Slab)
+    Snap->Pointers.push_back(&Sym);
+  auto S = std::shared_ptr<std::vector<const Symbol *>>(std::move(Snap),
+                                                        &Snap->Pointers);
+  auto MemIdx = llvm::make_unique<MemIndex>();
+  MemIdx->build(std::move(S));
+  return std::move(MemIdx);
+}
+
 } // namespace clangd
 } // namespace clang
Index: clangd/CodeComplete.h
===================================================================
--- clangd/CodeComplete.h
+++ clangd/CodeComplete.h
@@ -67,6 +67,12 @@
   /// FIXME(ioeric): we might want a better way to pass the index around inside
   /// clangd.
   const SymbolIndex *Index = nullptr;
+
+  /// Static index for project-wide global symbols. It is set by the clangd
+  /// client.
+  /// The static index is loaded and built only once when clangd is being
+  /// launched.
+  const SymbolIndex *StaticIndex = nullptr;
 };
 
 /// Get code completions at a specified \p Pos in \p FileName.
Index: clangd/CodeComplete.cpp
===================================================================
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -569,7 +569,8 @@
   return Item;
 }
 
-void completeWithIndex(const Context &Ctx, const SymbolIndex &Index,
+void completeWithIndex(const Context &Ctx,
+                       const CodeCompleteOptions &CompleteOptions,
                        llvm::StringRef Code, const SpecifiedScope &SSInfo,
                        llvm::StringRef Filter, CompletionList *Items) {
   FuzzyFindRequest Req;
@@ -579,9 +580,18 @@
   StringRef Scope = SSInfo.Resolved.empty() ? SSInfo.Written : SSInfo.Resolved;
   Req.Scopes = {Scope.trim(':').str()};
 
-  Items->isIncomplete = !Index.fuzzyFind(Ctx, Req, [&](const Symbol &Sym) {
-    Items->items.push_back(indexCompletionItem(Sym, Filter, SSInfo));
-  });
+  // FIXME: figure out a way to merge the symbols from dynamic index and static
+  // index.
+  if (CompleteOptions.Index)
+    Items->isIncomplete =
+        !CompleteOptions.Index->fuzzyFind(Ctx, Req, [&](const Symbol &Sym) {
+          Items->items.push_back(indexCompletionItem(Sym, Filter, SSInfo));
+        });
+  if (CompleteOptions.StaticIndex)
+    Items->isIncomplete = !CompleteOptions.StaticIndex->fuzzyFind(
+        Ctx, Req, [&](const Symbol &Sym) {
+          Items->items.push_back(indexCompletionItem(Sym, Filter, SSInfo));
+        });
 }
 
 SpecifiedScope extraCompletionScope(Sema &S, const CXXScopeSpec &SS) {
@@ -633,12 +643,13 @@
   invokeCodeComplete(Ctx, std::move(Consumer), Opts.getClangCompleteOpts(),
                      FileName, Command, Preamble, Contents, Pos, std::move(VFS),
                      std::move(PCHs));
-  if (Opts.Index && CompletedName.SSInfo) {
+  if (CompletedName.SSInfo && (Opts.Index || Opts.StaticIndex)) {
     if (!Results.items.empty())
       log(Ctx, "WARNING: Got completion results from sema for completion on "
                "qualified ID while symbol index is provided.");
     Results.items.clear();
-    completeWithIndex(Ctx, *Opts.Index, Contents, *CompletedName.SSInfo,
+
+    completeWithIndex(Ctx, Opts, Contents, *CompletedName.SSInfo,
                       CompletedName.Filter, &Results);
   }
   return Results;
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -205,6 +205,7 @@
                FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
                bool StorePreamblesInMemory,
                bool BuildDynamicSymbolIndex = false,
+               std::unique_ptr<SymbolIndex> GlobalIdx = nullptr,
                llvm::Optional<StringRef> ResourceDir = llvm::None);
 
   /// Set the root path of the workspace.
@@ -338,6 +339,7 @@
   DraftStore DraftMgr;
   /// If set, this manages index for symbols in opened files.
   std::unique_ptr<FileIndex> FileIdx;
+  std::unique_ptr<SymbolIndex> GlobalIdx;
   CppFileCollection Units;
   std::string ResourceDir;
   // If set, this represents the workspace path.
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -135,9 +135,11 @@
                            unsigned AsyncThreadsCount,
                            bool StorePreamblesInMemory,
                            bool BuildDynamicSymbolIndex,
+                           std::unique_ptr<SymbolIndex> GlobalIdx,
                            llvm::Optional<StringRef> ResourceDir)
     : CDB(CDB), DiagConsumer(DiagConsumer), FSProvider(FSProvider),
       FileIdx(BuildDynamicSymbolIndex ? new FileIndex() : nullptr),
+      GlobalIdx(std::move(GlobalIdx)),
       // Pass a callback into `Units` to extract symbols from a newly parsed
       // file and rebuild the file index synchronously each time an AST is
       // parsed.
@@ -251,6 +253,8 @@
   auto CodeCompleteOpts = Opts;
   if (FileIdx)
     CodeCompleteOpts.Index = FileIdx.get();
+  if (GlobalIdx)
+    CodeCompleteOpts.StaticIndex = GlobalIdx.get();
   // A task that will be run asynchronously.
   auto Task =
       // 'mutable' to reassign Preamble variable.
Index: clangd/ClangdLSPServer.h
===================================================================
--- clangd/ClangdLSPServer.h
+++ clangd/ClangdLSPServer.h
@@ -22,6 +22,7 @@
 namespace clangd {
 
 class JSONOutput;
+class SymbolIndex;
 
 /// This class provides implementation of an LSP server, glueing the JSON
 /// dispatch and ClangdServer together.
@@ -35,7 +36,8 @@
                   const clangd::CodeCompleteOptions &CCOpts,
                   llvm::Optional<StringRef> ResourceDir,
                   llvm::Optional<Path> CompileCommandsDir,
-                  bool BuildDynamicSymbolIndex);
+                  bool BuildDynamicSymbolIndex,
+                  std::unique_ptr<SymbolIndex> GlobalIdx);
 
   /// Run LSP server loop, receiving input for it from \p In. \p In must be
   /// opened in binary mode. Output will be written using Out variable passed to
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -283,10 +283,12 @@
                                  const clangd::CodeCompleteOptions &CCOpts,
                                  llvm::Optional<StringRef> ResourceDir,
                                  llvm::Optional<Path> CompileCommandsDir,
-                                 bool BuildDynamicSymbolIndex)
+                                 bool BuildDynamicSymbolIndex,
+                                 std::unique_ptr<SymbolIndex> GlobalIdx)
     : Out(Out), CDB(std::move(CompileCommandsDir)), CCOpts(CCOpts),
       Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount,
-             StorePreamblesInMemory, BuildDynamicSymbolIndex, ResourceDir) {}
+             StorePreamblesInMemory, BuildDynamicSymbolIndex,
+             std::move(GlobalIdx), ResourceDir) {}
 
 bool ClangdLSPServer::run(std::istream &In) {
   assert(!IsDone && "Run was called before");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to