ioeric created this revision.
Herald added subscribers: ilya-biryukov, mgorny.
o Experimental interfaces to support use multiple index sources (e.g. AST index,
global index) for code completion, cross-reference finding etc.
o Replace sema code completion for qualified-id with index-based completion.


https://reviews.llvm.org/D40548

Files:
  clangd/ASTIndex.cpp
  clangd/ASTIndex.h
  clangd/CMakeLists.txt
  clangd/ClangdIndex.cpp
  clangd/ClangdIndex.h
  clangd/ClangdLSPServer.cpp
  clangd/ClangdLSPServer.h
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/ClangdUnit.cpp
  clangd/ClangdUnit.h
  clangd/ClangdUnitStore.cpp
  clangd/ClangdUnitStore.h
  clangd/SymbolIndex.h
  clangd/tool/ClangdMain.cpp

Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -160,7 +160,7 @@
   // Initialize and run ClangdLSPServer.
   ClangdLSPServer LSPServer(Out, WorkerThreadsCount, StorePreamblesInMemory,
                             EnableSnippets, ResourceDirRef,
-                            CompileCommandsDirPath);
+                            CompileCommandsDirPath, {});
   constexpr int NoShutdownRequestErrorCode = 1;
   llvm::set_thread_name("clangd.main");
   return LSPServer.run(std::cin) ? 0 : NoShutdownRequestErrorCode;
Index: clangd/SymbolIndex.h
===================================================================
--- /dev/null
+++ clangd/SymbolIndex.h
@@ -0,0 +1,57 @@
+//===--- CompletionIndex.h - Index for code completion -----------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPLETIONINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPLETIONINDEX_H
+
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+
+struct CompletionRequest {
+  std::string Query;
+  std::vector<std::string> FixedPrefixes;
+};
+
+struct ScoreSignals {
+  float fuzzy_score;
+};
+
+struct CompletionSymbol {
+  ScoreSignals Signals;
+
+  std::string UID;
+  std::string QualifiedName;
+};
+
+struct CompletionResult {
+  //std::vector<CompletionSymbol> Symbol;
+  std::vector<std::string> Symbols;
+  bool all_matched;
+};
+
+class SymbolIndex {
+public:
+  virtual ~SymbolIndex() = default;
+
+  virtual llvm::Expected<CompletionResult>
+  complete(const CompletionRequest &Req) const = 0;
+
+  virtual llvm::Expected<std::string>
+  getSymbolInfo(llvm::StringRef UID) const = 0;
+
+  virtual llvm::Expected<std::vector<std::string>>
+  getAllOccurrences(llvm::StringRef UID) const = 0;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPLETIONINDEX_H
Index: clangd/ClangdUnitStore.h
===================================================================
--- clangd/ClangdUnitStore.h
+++ clangd/ClangdUnitStore.h
@@ -12,6 +12,7 @@
 
 #include <mutex>
 
+#include "ASTIndex.h"
 #include "ClangdUnit.h"
 #include "GlobalCompilationDatabase.h"
 #include "Path.h"
@@ -25,11 +26,14 @@
 /// Thread-safe mapping from FileNames to CppFile.
 class CppFileCollection {
 public:
+  explicit CppFileCollection(ASTIndexSourcer *IndexSourcer)
+      : IndexSourcer(IndexSourcer) {}
+
   std::shared_ptr<CppFile>
   getOrCreateFile(PathRef File, PathRef ResourceDir,
                   GlobalCompilationDatabase &CDB, bool StorePreamblesInMemory,
                   std::shared_ptr<PCHContainerOperations> PCHs,
-                  clangd::Logger &Logger) {
+                  clangd::Logger &Logger, ASTIndexSourcer *IndexSourcer) {
     std::lock_guard<std::mutex> Lock(Mutex);
 
     auto It = OpenedFiles.find(File);
@@ -39,7 +43,8 @@
       It = OpenedFiles
                .try_emplace(File, CppFile::Create(File, std::move(Command),
                                                   StorePreamblesInMemory,
-                                                  std::move(PCHs), Logger))
+                                                  std::move(PCHs), Logger,
+                                                  IndexSourcer))
                .first;
     }
     return It->second;
@@ -86,6 +91,7 @@
 
   std::mutex Mutex;
   llvm::StringMap<std::shared_ptr<CppFile>> OpenedFiles;
+  ASTIndexSourcer *IndexSourcer;
 };
 } // namespace clangd
 } // namespace clang
Index: clangd/ClangdUnitStore.cpp
===================================================================
--- clangd/ClangdUnitStore.cpp
+++ clangd/ClangdUnitStore.cpp
@@ -23,6 +23,7 @@
 
   std::shared_ptr<CppFile> Result = It->second;
   OpenedFiles.erase(It);
+  IndexSourcer->remove(File);
   return Result;
 }
 
@@ -42,14 +43,15 @@
     It = OpenedFiles
              .try_emplace(File, CppFile::Create(File, std::move(NewCommand),
                                                 StorePreamblesInMemory,
-                                                std::move(PCHs), Logger))
+                                                std::move(PCHs), Logger,
+                                                IndexSourcer))
              .first;
   } else if (!compileCommandsAreEqual(It->second->getCompileCommand(),
                                       NewCommand)) {
     Result.RemovedFile = std::move(It->second);
     It->second =
         CppFile::Create(File, std::move(NewCommand), StorePreamblesInMemory,
-                        std::move(PCHs), Logger);
+                        std::move(PCHs), Logger, IndexSourcer);
   }
   Result.FileInCollection = It->second;
   return Result;
Index: clangd/ClangdUnit.h
===================================================================
--- clangd/ClangdUnit.h
+++ clangd/ClangdUnit.h
@@ -10,6 +10,8 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
 
+#include "ASTIndex.h"
+#include "ClangdIndex.h"
 #include "Function.h"
 #include "Path.h"
 #include "Protocol.h"
@@ -144,12 +146,14 @@
   static std::shared_ptr<CppFile>
   Create(PathRef FileName, tooling::CompileCommand Command,
          bool StorePreamblesInMemory,
-         std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger);
+         std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger,
+         ASTIndexSourcer *IndexSourcer);
 
 private:
   CppFile(PathRef FileName, tooling::CompileCommand Command,
           bool StorePreamblesInMemory,
-          std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger);
+          std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger,
+          ASTIndexSourcer *IndexSourcer);
 
 public:
   CppFile(CppFile const &) = delete;
@@ -207,6 +211,8 @@
   /// Get CompileCommand used to build this CppFile.
   tooling::CompileCommand const &getCompileCommand() const;
 
+  const ASTIndexSourcer &getASTIndexSourcer() { return *IndexSourcer; }
+
 private:
   /// A helper guard that manages the state of CppFile during rebuild.
   class RebuildGuard {
@@ -252,6 +258,8 @@
   std::shared_ptr<PCHContainerOperations> PCHs;
   /// Used for logging various messages.
   clangd::Logger &Logger;
+
+  ASTIndexSourcer *IndexSourcer;
 };
 
 struct CodeCompleteOptions {
@@ -282,7 +290,7 @@
   bool IncludeMacros = true;
 
   /// Add globals to code completion results.
-  bool IncludeGlobals = true;
+  bool IncludeGlobals = false;
 
   /// Add brief comments to completion items, if available.
   /// FIXME(ibiryukov): it looks like turning this option on significantly slows
@@ -295,12 +303,14 @@
 };
 
 /// Get code completions at a specified \p Pos in \p FileName.
-CompletionList
-codeComplete(PathRef FileName, const tooling::CompileCommand &Command,
-             PrecompiledPreamble const *Preamble, StringRef Contents,
-             Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
-             std::shared_ptr<PCHContainerOperations> PCHs,
-             clangd::CodeCompleteOptions Opts, clangd::Logger &Logger);
+CompletionList codeComplete(PathRef FileName,
+                            const tooling::CompileCommand &Command,
+                            PrecompiledPreamble const *Preamble,
+                            StringRef Contents, Position Pos,
+                            IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+                            std::shared_ptr<PCHContainerOperations> PCHs,
+                            clangd::CodeCompleteOptions Opts,
+                            clangd::Logger &Logger, const SymbolIndex &Index);
 
 /// Get signature help at a specified \p Pos in \p FileName.
 SignatureHelp signatureHelp(PathRef FileName,
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -9,6 +9,7 @@
 
 #include "ClangdUnit.h"
 
+#include "ClangdServer.h"
 #include "Logger.h"
 #include "Trace.h"
 #include "clang/Frontend/CompilerInstance.h"
@@ -424,17 +425,24 @@
 class CompletionItemsCollector : public CodeCompleteConsumer {
 public:
   CompletionItemsCollector(const clangd::CodeCompleteOptions &CodeCompleteOpts,
-                           CompletionList &Items)
+                           CompletionList &Items, const SymbolIndex &Index)
       : CodeCompleteConsumer(CodeCompleteOpts.getClangCompleteOpts(),
                              /*OutputIsBinary=*/false),
         ClangdOpts(CodeCompleteOpts), Items(Items),
         Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
-        CCTUInfo(Allocator) {}
+        CCTUInfo(Allocator), Index(Index) {}
 
   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
                                   CodeCompletionResult *Results,
                                   unsigned NumResults) override final {
     std::priority_queue<CompletionCandidate> Candidates;
+    if (auto OptSS = Context.getCXXScopeSpec()) {
+      if (NumResults > 0)
+        llvm::errs() << "[CompletionItemsCollector] Expect no completion "
+                        "result for qualified/global completion. Got "
+                     << NumResults << " results.\n";
+      return doGlobalCompletion(S, **OptSS);
+    }
     for (unsigned I = 0; I < NumResults; ++I) {
       Candidates.emplace(Results[I]);
       if (ClangdOpts.Limit && Candidates.size() > ClangdOpts.Limit) {
@@ -481,14 +489,85 @@
     return Item;
   }
 
+  void doGlobalCompletion(Sema &S, CXXScopeSpec &SS) {
+      llvm::errs() << "[QualifiedCompletion]\n";
+      std::string WrittenSS = Lexer::getSourceText(
+                            CharSourceRange::getCharRange(SS.getRange()),
+                            S.getSourceManager(), clang::LangOptions());
+
+      if (SS.isInvalid()) {
+        llvm::errs() << "  Invalid SS: [" << WrittenSS << "]";
+      } else {
+        llvm::errs() << "  Valid SS: [" << WrittenSS << "]";
+      }
+      std::string InferredSpecifier;
+      if (SS.isValid()) {
+        llvm::errs() << "  Got CXXScopeSpec.\n";
+        DeclContext *DC = S.computeDeclContext(SS);
+        if (auto *NS = llvm::dyn_cast<NamespaceDecl>(DC)) {
+          InferredSpecifier = NS->getQualifiedNameAsString();
+          llvm::errs() << "  Namespace: " << InferredSpecifier << "\n";
+        } else if (auto *TU = llvm::dyn_cast<TranslationUnitDecl>(DC)) {
+          InferredSpecifier = "";
+          llvm::errs() << "  TU\n";
+        }
+      }
+
+      if (InferredSpecifier != WrittenSS)
+        llvm::errs() << "WriitenSS != InferredSpecifier: [" << WrittenSS
+                     << "] vs [" << InferredSpecifier << "]\n";
+
+      std::string Query =
+          InferredSpecifier.empty() ? WrittenSS : InferredSpecifier;
+      auto Filter = S.getPreprocessor().getCodeCompletionFilter();
+      if (!Filter.empty())
+        Query += "::" + Filter.str();
+      llvm::errs() << "  Query: [" << Query << "], "
+                   << "Filter: [" << Filter << "]\n";
+      CompletionRequest Req;
+      Req.Query = Query;
+      llvm::Expected<CompletionResult> Result = Index.complete(Req);
+      if (!Result) {
+        llvm::errs() << "  Failed to complete [" << Req.Query
+                     << "]. Error: " << llvm::toString(Result.takeError())
+                     << "\n";
+        return;
+      }
+      for (unsigned i = 0; i < Result->Symbols.size(); ++i) {
+        CompletionItem item;
+        llvm::StringRef QualifiedName = Result->Symbols[i];
+        item.label = QualifiedName;
+        item.kind = CompletionItemKind::Class;
+        item.detail = QualifiedName;
+        TextEdit Edit;
+        Edit.newText = llvm::StringRef(WrittenSS).startswith("::")
+                           ? ("::" + QualifiedName).str()
+                           : QualifiedName.str();
+        SourceRange SR = SS.getRange();
+        auto &SM = S.getSourceManager();
+        FileID FID = SM.getFileID(SR.getBegin());
+        const auto *FE = SM.getFileEntryForID(FID);
+        llvm::MemoryBuffer *Buffer = SM.getMemoryBufferForFile(FE);
+        llvm::StringRef Code = Buffer->getBuffer();
+        Edit.range.start =
+            offsetToPosition(Code, SM.getFileOffset(SR.getBegin()));
+        Edit.range.end = offsetToPosition(Code, SM.getFileOffset(SR.getEnd()));
+        item.textEdit = std::move(Edit);
+        item.sortText = std::to_string(i);
+        item.insertTextFormat = InsertTextFormat::PlainText;
+        Items.items.push_back(std::move(item));
+      }
+      Items.isIncomplete = true;
+  }
+
   virtual void ProcessChunks(const CodeCompletionString &CCS,
                              CompletionItem &Item) const = 0;
 
   clangd::CodeCompleteOptions ClangdOpts;
   CompletionList &Items;
   std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
   CodeCompletionTUInfo CCTUInfo;
-
+  const SymbolIndex &Index;
 }; // CompletionItemsCollector
 
 bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) {
@@ -502,8 +581,8 @@
 public:
   PlainTextCompletionItemsCollector(
       const clangd::CodeCompleteOptions &CodeCompleteOpts,
-      CompletionList &Items)
-      : CompletionItemsCollector(CodeCompleteOpts, Items) {}
+      CompletionList &Items, const SymbolIndex &Index)
+      : CompletionItemsCollector(CodeCompleteOpts, Items, Index) {}
 
 private:
   void ProcessChunks(const CodeCompletionString &CCS,
@@ -539,8 +618,8 @@
 public:
   SnippetCompletionItemsCollector(
       const clangd::CodeCompleteOptions &CodeCompleteOpts,
-      CompletionList &Items)
-      : CompletionItemsCollector(CodeCompleteOpts, Items) {}
+      CompletionList &Items, const SymbolIndex &Index)
+      : CompletionItemsCollector(CodeCompleteOpts, Items, Index) {}
 
 private:
   void ProcessChunks(const CodeCompletionString &CCS,
@@ -838,15 +917,16 @@
                      PrecompiledPreamble const *Preamble, StringRef Contents,
                      Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
                      std::shared_ptr<PCHContainerOperations> PCHs,
-                     clangd::CodeCompleteOptions Opts, clangd::Logger &Logger) {
+                     clangd::CodeCompleteOptions Opts, clangd::Logger &Logger,
+                     const SymbolIndex &Index) {
   CompletionList Results;
   std::unique_ptr<CodeCompleteConsumer> Consumer;
   if (Opts.EnableSnippets) {
-    Consumer =
-        llvm::make_unique<SnippetCompletionItemsCollector>(Opts, Results);
+    Consumer = llvm::make_unique<SnippetCompletionItemsCollector>(Opts, Results,
+                                                                  Index);
   } else {
-    Consumer =
-        llvm::make_unique<PlainTextCompletionItemsCollector>(Opts, Results);
+    Consumer = llvm::make_unique<PlainTextCompletionItemsCollector>(
+        Opts, Results, Index);
   }
   invokeCodeComplete(std::move(Consumer), Opts.getClangCompleteOpts(), FileName,
                      Command, Preamble, Contents, Pos, std::move(VFS),
@@ -1139,19 +1219,23 @@
 CppFile::Create(PathRef FileName, tooling::CompileCommand Command,
                 bool StorePreamblesInMemory,
                 std::shared_ptr<PCHContainerOperations> PCHs,
-                clangd::Logger &Logger) {
-  return std::shared_ptr<CppFile>(new CppFile(FileName, std::move(Command),
-                                              StorePreamblesInMemory,
-                                              std::move(PCHs), Logger));
+                clangd::Logger &Logger, ASTIndexSourcer *IndexSourcer) {
+  return std::shared_ptr<CppFile>(
+      new CppFile(FileName, std::move(Command), StorePreamblesInMemory,
+                  std::move(PCHs), Logger, IndexSourcer));
 }
 
 CppFile::CppFile(PathRef FileName, tooling::CompileCommand Command,
                  bool StorePreamblesInMemory,
                  std::shared_ptr<PCHContainerOperations> PCHs,
-                 clangd::Logger &Logger)
+                 clangd::Logger &Logger, ASTIndexSourcer *IndexSourcer)
     : FileName(FileName), Command(std::move(Command)),
       StorePreamblesInMemory(StorePreamblesInMemory), RebuildCounter(0),
-      RebuildInProgress(false), PCHs(std::move(PCHs)), Logger(Logger) {
+      RebuildInProgress(false), PCHs(std::move(PCHs)), Logger(Logger),
+      IndexSourcer(IndexSourcer) {
+
+  llvm::errs() << "[Completion] Creating CppFile " << FileName
+               << " with IndexSourcer: " << IndexSourcer << "\n";
 
   std::lock_guard<std::mutex> Lock(Mutex);
   LatestAvailablePreamble = nullptr;
@@ -1350,6 +1434,8 @@
     if (NewAST) {
       Diagnostics.insert(Diagnostics.end(), NewAST->getDiagnostics().begin(),
                          NewAST->getDiagnostics().end());
+      That->IndexSourcer->update(That->FileName, NewAST->getASTContext(),
+                                 NewAST->getTopLevelDecls());
     } else {
       // Don't report even Preamble diagnostics if we coulnd't build AST.
       Diagnostics.clear();
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
 
+#include "ClangdIndex.h"
 #include "ClangdUnitStore.h"
 #include "DraftStore.h"
 #include "GlobalCompilationDatabase.h"
@@ -209,13 +210,15 @@
   /// clangd are stored in-memory or on disk.
   ///
   /// Various messages are logged using \p Logger.
-  ClangdServer(GlobalCompilationDatabase &CDB,
-               DiagnosticsConsumer &DiagConsumer,
-               FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
-               bool StorePreamblesInMemory,
-               clangd::CodeCompleteOptions CodeCompleteOpts,
-               clangd::Logger &Logger,
-               llvm::Optional<StringRef> ResourceDir = llvm::None);
+  ClangdServer(
+      GlobalCompilationDatabase &CDB, DiagnosticsConsumer &DiagConsumer,
+      FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
+      bool StorePreamblesInMemory, clangd::CodeCompleteOptions CodeCompleteOpts,
+      clangd::Logger &Logger,
+      std::vector<
+          std::pair<llvm::StringRef, CombinedSymbolIndex::WeightedIndex>>
+          AdditionalIndexes,
+      llvm::Optional<StringRef> ResourceDir = llvm::None);
 
   /// Set the root path of the workspace.
   void setRootPath(PathRef RootPath);
@@ -324,7 +327,10 @@
   DiagnosticsConsumer &DiagConsumer;
   FileSystemProvider &FSProvider;
   DraftStore DraftMgr;
+
+  ASTIndexSourcer IndexSourcer;
   CppFileCollection Units;
+
   std::string ResourceDir;
   // If set, this represents the workspace path.
   llvm::Optional<std::string> RootPath;
@@ -341,6 +347,8 @@
   // called before all other members to stop the worker thread that references
   // ClangdServer
   ClangdScheduler WorkScheduler;
+
+  CombinedSymbolIndex CombinedIndex;
 };
 
 } // namespace clangd
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -173,13 +173,24 @@
     GlobalCompilationDatabase &CDB, DiagnosticsConsumer &DiagConsumer,
     FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
     bool StorePreamblesInMemory, clangd::CodeCompleteOptions CodeCompleteOpts,
-    clangd::Logger &Logger, llvm::Optional<StringRef> ResourceDir)
+    clangd::Logger &Logger,
+    std::vector<std::pair<llvm::StringRef, CombinedSymbolIndex::WeightedIndex>>
+        AdditionalIndexes,
+    llvm::Optional<StringRef> ResourceDir)
     : Logger(Logger), CDB(CDB), DiagConsumer(DiagConsumer),
-      FSProvider(FSProvider),
+      FSProvider(FSProvider), Units(&IndexSourcer),
       ResourceDir(ResourceDir ? ResourceDir->str() : getStandardResourceDir()),
       PCHs(std::make_shared<PCHContainerOperations>()),
       StorePreamblesInMemory(StorePreamblesInMemory),
-      CodeCompleteOpts(CodeCompleteOpts), WorkScheduler(AsyncThreadsCount) {}
+      CodeCompleteOpts(CodeCompleteOpts), WorkScheduler(AsyncThreadsCount) {
+  CombinedSymbolIndex::WeightedIndex WeightedASTIndex(
+      llvm::make_unique<ASTSymbolIndex>(&IndexSourcer));
+  WeightedASTIndex.OverallWeight = 10;
+  CombinedIndex.addSymbolIndex("AST", std::move(WeightedASTIndex));
+  for (auto &Index : AdditionalIndexes) {
+    CombinedIndex.addSymbolIndex(Index.first, std::move(Index.second));
+  }
+}
 
 void ClangdServer::setRootPath(PathRef RootPath) {
   std::string NewRootPath = llvm::sys::path::convert_to_slash(
@@ -192,8 +203,9 @@
   DocVersion Version = DraftMgr.updateDraft(File, Contents);
 
   auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-  std::shared_ptr<CppFile> Resources = Units.getOrCreateFile(
-      File, ResourceDir, CDB, StorePreamblesInMemory, PCHs, Logger);
+  std::shared_ptr<CppFile> Resources =
+      Units.getOrCreateFile(File, ResourceDir, CDB, StorePreamblesInMemory,
+                            PCHs, Logger, &IndexSourcer);
   return scheduleReparseAndDiags(File, VersionedDraft{Version, Contents.str()},
                                  std::move(Resources), std::move(TaggedFS));
 }
@@ -284,7 +296,7 @@
         CompletionList Result = clangd::codeComplete(
             File, Resources->getCompileCommand(),
             Preamble ? &Preamble->Preamble : nullptr, Contents, Pos,
-            TaggedFS.Value, PCHs, CodeCompleteOpts, Logger);
+            TaggedFS.Value, PCHs, CodeCompleteOpts, Logger, CombinedIndex);
 
         Callback(make_tagged(std::move(Result), std::move(TaggedFS.Tag)));
       };
Index: clangd/ClangdLSPServer.h
===================================================================
--- clangd/ClangdLSPServer.h
+++ clangd/ClangdLSPServer.h
@@ -30,10 +30,13 @@
   /// If \p CompileCommandsDir has a value, compile_commands.json will be
   /// loaded only from \p CompileCommandsDir. Otherwise, clangd will look
   /// for compile_commands.json in all parent directories of each file.
-  ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount,
-                  bool StorePreamblesInMemory, bool SnippetCompletions,
-                  llvm::Optional<StringRef> ResourceDir,
-                  llvm::Optional<Path> CompileCommandsDir);
+  ClangdLSPServer(
+      JSONOutput &Out, unsigned AsyncThreadsCount, bool StorePreamblesInMemory,
+      bool SnippetCompletions, llvm::Optional<StringRef> ResourceDir,
+      llvm::Optional<Path> CompileCommandsDir,
+      std::vector<
+          std::pair<llvm::StringRef, CombinedSymbolIndex::WeightedIndex>>
+          AdditionalIndexes);
 
   /// 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
@@ -234,17 +234,18 @@
   C.reply(Result ? URI::fromFile(*Result).uri : "");
 }
 
-ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount,
-                                 bool StorePreamblesInMemory,
-                                 bool SnippetCompletions,
-                                 llvm::Optional<StringRef> ResourceDir,
-                                 llvm::Optional<Path> CompileCommandsDir)
+ClangdLSPServer::ClangdLSPServer(
+    JSONOutput &Out, unsigned AsyncThreadsCount, bool StorePreamblesInMemory,
+    bool SnippetCompletions, llvm::Optional<StringRef> ResourceDir,
+    llvm::Optional<Path> CompileCommandsDir,
+    std::vector<std::pair<llvm::StringRef, CombinedSymbolIndex::WeightedIndex>>
+        AdditionalIndexes)
     : Out(Out), CDB(/*Logger=*/Out, std::move(CompileCommandsDir)),
       Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount,
              StorePreamblesInMemory,
              clangd::CodeCompleteOptions(
                  /*EnableSnippetsAndCodePatterns=*/SnippetCompletions),
-             /*Logger=*/Out, ResourceDir) {}
+             /*Logger=*/Out, std::move(AdditionalIndexes), ResourceDir) {}
 
 bool ClangdLSPServer::run(std::istream &In) {
   assert(!IsDone && "Run was called before");
Index: clangd/ClangdIndex.h
===================================================================
--- /dev/null
+++ clangd/ClangdIndex.h
@@ -0,0 +1,56 @@
+//===--- ClangdIndex.h - Symbol indexes for clangd.---------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDINDEX_H
+
+#include "SymbolIndex.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+
+class CombinedSymbolIndex : public SymbolIndex {
+public:
+  CombinedSymbolIndex() = default;
+
+  struct WeightedIndex {
+    explicit WeightedIndex(std::unique_ptr<SymbolIndex> Index)
+        : Index(std::move(Index)) {}
+
+    std::unique_ptr<SymbolIndex> Index;
+    double OverallWeight;
+  };
+
+  void addSymbolIndex(llvm::StringRef Label, WeightedIndex Index);
+
+  llvm::Expected<CompletionResult>
+  complete(const CompletionRequest &Req) const override;
+
+  llvm::Expected<std::string>
+  getSymbolInfo(llvm::StringRef UID) const override {
+    // FIXME(ioeric): implement this.
+    return "";
+  }
+
+  llvm::Expected<std::vector<std::string>>
+  getAllOccurrences(llvm::StringRef UID) const override {
+    // FIXME(ioeric): implement this.
+    return std::vector<std::string>();
+  }
+
+private:
+  llvm::StringMap<WeightedIndex> Indexes;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDINDEX_H
Index: clangd/ClangdIndex.cpp
===================================================================
--- /dev/null
+++ clangd/ClangdIndex.cpp
@@ -0,0 +1,42 @@
+//===--- ClangdIndex.cpp - Symbol indexes for clangd. ------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#include "ClangdIndex.h"
+
+namespace clang {
+namespace clangd {
+
+void CombinedSymbolIndex::addSymbolIndex(
+    llvm::StringRef Label, CombinedSymbolIndex::WeightedIndex Index) {
+  Indexes.insert({Label, std::move(Index)});
+}
+
+llvm::Expected<CompletionResult>
+CombinedSymbolIndex::complete(const CompletionRequest &Req) const {
+  CompletionResult Result;
+  // FIXME(ioeric): Consider ranking signals and index weights.
+  for (auto &Entry : Indexes) {
+    const WeightedIndex &Index = Entry.second;
+    auto Res = Index.Index->complete(Req);
+    if (!Res) {
+      llvm::errs() << "Failed to complete request " << Req.Query << " in index "
+                   << Entry.first() << "\n";
+      continue;
+    }
+    // FIXME(ioeric): figure out what to do with `all_matched`.
+
+    // FIXME(ioeric): for now, we simply merge results from all indexes.
+    Result.Symbols.insert(Result.Symbols.end(), Res->Symbols.begin(),
+                          Res->Symbols.end());
+  }
+  return Result;
+}
+
+} // namespace clangd
+} // namespace clang
Index: clangd/CMakeLists.txt
===================================================================
--- clangd/CMakeLists.txt
+++ clangd/CMakeLists.txt
@@ -3,6 +3,8 @@
   )
 
 add_clang_library(clangDaemon
+  ASTIndex.cpp
+  ClangdIndex.cpp
   ClangdLSPServer.cpp
   ClangdServer.cpp
   ClangdUnit.cpp
Index: clangd/ASTIndex.h
===================================================================
--- /dev/null
+++ clangd/ASTIndex.h
@@ -0,0 +1,63 @@
+//===--- ASTIndex.h - Indexes for AST symbols. -----------*- C++-*-===========//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTINDEX_H
+
+#include "Path.h"
+#include "SymbolIndex.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/StringMap.h"
+#include <mutex>
+
+namespace clang {
+namespace clangd {
+
+class ASTIndexSourcer {
+ public:
+   ASTIndexSourcer() = default;
+
+   void remove(PathRef Path);
+
+   void update(PathRef Path, ASTContext &Context,
+               llvm::ArrayRef<const Decl *> TopLevelDecls);
+
+   CompletionResult complete(llvm::StringRef Query) const;
+
+ private:
+   llvm::StringMap<std::set<std::string>> Symbols;
+   mutable std::mutex Mutex;
+};
+
+class ASTSymbolIndex : public SymbolIndex {
+public:
+  ASTSymbolIndex(ASTIndexSourcer *Sourcer);
+
+  llvm::Expected<CompletionResult>
+  complete(const CompletionRequest &Req) const override;
+
+  llvm::Expected<std::string>
+  getSymbolInfo(llvm::StringRef UID) const override {
+    // FIXME(ioeric): implement this.
+    return "";
+  }
+
+  llvm::Expected<std::vector<std::string>>
+  getAllOccurrences(llvm::StringRef UID) const override {
+    // FIXME(ioeric): implement this.
+    return std::vector<std::string>();
+  }
+
+private:
+  ASTIndexSourcer *Sourcer;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTINDEX_H
Index: clangd/ASTIndex.cpp
===================================================================
--- /dev/null
+++ clangd/ASTIndex.cpp
@@ -0,0 +1,89 @@
+#include "ASTIndex.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexingAction.h"
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+class IndexConsumer : public index::IndexDataConsumer {
+public:
+  IndexConsumer(std::set<std::string> &Symbols) : Symbols(Symbols) {}
+
+  bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
+                           ArrayRef<index::SymbolRelation> Relations,
+                           FileID FID, unsigned Offset,
+                           ASTNodeInfo ASTNode) override {
+    if (!(Roles & (unsigned)index::SymbolRole::Declaration ||
+          Roles & (unsigned)index::SymbolRole::Definition)) {
+      return true;
+    }
+    if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) {
+      Symbols.insert(ND->getQualifiedNameAsString());
+    }
+    return true;
+  }
+
+private:
+  std::set<std::string> &Symbols;
+};
+
+} // namespace
+
+void ASTIndexSourcer::remove(PathRef Path) {
+  std::lock_guard<std::mutex> Lock(Mutex);
+  Symbols.erase(Path);
+}
+
+void ASTIndexSourcer::update(PathRef Path, ASTContext &Ctx,
+                             llvm::ArrayRef<const Decl *> TopLevelDecls) {
+  std::set<std::string> TUSymbols;
+  {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    auto Consumer = std::make_shared<IndexConsumer>(TUSymbols);
+    index::IndexingOptions IndexOpts;
+    IndexOpts.SystemSymbolFilter =
+        index::IndexingOptions::SystemSymbolFilterKind::All;
+
+    index::indexTopLevelDecls(Ctx, TopLevelDecls, Consumer, IndexOpts);
+  }
+  llvm::errs() << "[ASTIndexSourcer] symbols updated. " << Path << ": "
+               << TUSymbols.size() << " symbols indexed.\n";
+  unsigned i = 0;
+  for (llvm::StringRef Symbol : TUSymbols) {
+    if (i++ > 10)
+      break;
+    llvm::errs() << " --- " << Symbol;
+  }
+  llvm::errs() << "\n";
+  Symbols[Path.str()] = std::move(TUSymbols);
+}
+
+CompletionResult ASTIndexSourcer::complete(llvm::StringRef Query) const {
+  CompletionResult Result;
+  // FIXME (ioeric): Do something about `all_matched`.
+  Result.all_matched = true;
+  {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    llvm::errs() << Symbols.size() << " symbols in the index.\n";
+    for (const auto &Pair : Symbols) {
+      for (llvm::StringRef Symbol : Pair.second) {
+        if (Symbol.contains(Query))
+          Result.Symbols.push_back(Symbol);
+      }
+    }
+  }
+  return Result;
+}
+
+ASTSymbolIndex::ASTSymbolIndex(ASTIndexSourcer *Sourcer)
+    : Sourcer(Sourcer) {}
+
+llvm::Expected<CompletionResult>
+ASTSymbolIndex::complete(const CompletionRequest &Req) const {
+  return Sourcer->complete(Req.Query);
+}
+
+} // namespace clangd
+} // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to