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 + +namespace clang { +namespace clangd { + +class ASTIndexSourcer { + public: + ASTIndexSourcer() = default; + + void remove(PathRef Path); + + void update(PathRef Path, ASTContext &Context, + llvm::ArrayRef TopLevelDecls); + + CompletionResult complete(llvm::StringRef Query) const; + + private: + llvm::StringMap> Symbols; + mutable std::mutex Mutex; +}; + +class ASTSymbolIndex : public SymbolIndex { +public: + ASTSymbolIndex(ASTIndexSourcer *Sourcer); + + llvm::Expected + complete(const CompletionRequest &Req) const override; + + llvm::Expected + getSymbolInfo(llvm::StringRef UID) const override { + // FIXME(ioeric): implement this. + return ""; + } + + llvm::Expected> + getAllOccurrences(llvm::StringRef UID) const override { + // FIXME(ioeric): implement this. + return std::vector(); + } + +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 &Symbols) : Symbols(Symbols) {} + + bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles, + ArrayRef 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(D)) { + Symbols.insert(ND->getQualifiedNameAsString()); + } + return true; + } + +private: + std::set &Symbols; +}; + +} // namespace + +void ASTIndexSourcer::remove(PathRef Path) { + std::lock_guard Lock(Mutex); + Symbols.erase(Path); +} + +void ASTIndexSourcer::update(PathRef Path, ASTContext &Ctx, + llvm::ArrayRef TopLevelDecls) { + std::set TUSymbols; + { + std::lock_guard Lock(Mutex); + auto Consumer = std::make_shared(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 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 +ASTSymbolIndex::complete(const CompletionRequest &Req) const { + return Sourcer->complete(Req.Query); +} + +} // 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/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 Index) + : Index(std::move(Index)) {} + + std::unique_ptr Index; + double OverallWeight; + }; + + void addSymbolIndex(llvm::StringRef Label, WeightedIndex Index); + + llvm::Expected + complete(const CompletionRequest &Req) const override; + + llvm::Expected + getSymbolInfo(llvm::StringRef UID) const override { + // FIXME(ioeric): implement this. + return ""; + } + + llvm::Expected> + getAllOccurrences(llvm::StringRef UID) const override { + // FIXME(ioeric): implement this. + return std::vector(); + } + +private: + llvm::StringMap 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 +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/ClangdLSPServer.h =================================================================== --- clangd/ClangdLSPServer.h +++ clangd/ClangdLSPServer.h @@ -30,11 +30,14 @@ /// 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, - const clangd::CodeCompleteOptions &CCOpts, - llvm::Optional ResourceDir, - llvm::Optional CompileCommandsDir); + ClangdLSPServer( + JSONOutput &Out, unsigned AsyncThreadsCount, bool StorePreamblesInMemory, + const clangd::CodeCompleteOptions &CCOpts, + llvm::Optional ResourceDir, + llvm::Optional CompileCommandsDir, + std::vector< + std::pair> + 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,15 +234,17 @@ C.reply(Result ? URI::fromFile(*Result).uri : ""); } -ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount, - bool StorePreamblesInMemory, - const clangd::CodeCompleteOptions &CCOpts, - llvm::Optional ResourceDir, - llvm::Optional CompileCommandsDir) +ClangdLSPServer::ClangdLSPServer( + JSONOutput &Out, unsigned AsyncThreadsCount, bool StorePreamblesInMemory, + const clangd::CodeCompleteOptions &CCOpts, + llvm::Optional ResourceDir, + llvm::Optional CompileCommandsDir, + std::vector> + AdditionalIndexes) : Out(Out), CDB(/*Logger=*/Out, std::move(CompileCommandsDir)), Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount, StorePreamblesInMemory, CCOpts, - /*Logger=*/Out, ResourceDir) {} + /*Logger=*/Out, std::move(AdditionalIndexes), ResourceDir) {} bool ClangdLSPServer::run(std::istream &In) { assert(!IsDone && "Run was called before"); 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" @@ -206,13 +207,16 @@ /// 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, - const clangd::CodeCompleteOptions &CodeCompleteOpts, - clangd::Logger &Logger, - llvm::Optional ResourceDir = llvm::None); + ClangdServer( + GlobalCompilationDatabase &CDB, DiagnosticsConsumer &DiagConsumer, + FileSystemProvider &FSProvider, unsigned AsyncThreadsCount, + bool StorePreamblesInMemory, + const clangd::CodeCompleteOptions &CodeCompleteOpts, + clangd::Logger &Logger, + std::vector< + std::pair> + AdditionalIndexes, + llvm::Optional ResourceDir = llvm::None); /// Set the root path of the workspace. void setRootPath(PathRef RootPath); @@ -321,7 +325,10 @@ DiagnosticsConsumer &DiagConsumer; FileSystemProvider &FSProvider; DraftStore DraftMgr; + + ASTIndexSourcer IndexSourcer; CppFileCollection Units; + std::string ResourceDir; // If set, this represents the workspace path. llvm::Optional RootPath; @@ -338,6 +345,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 @@ -169,20 +169,28 @@ Worker.join(); } -ClangdServer::ClangdServer(GlobalCompilationDatabase &CDB, - DiagnosticsConsumer &DiagConsumer, - FileSystemProvider &FSProvider, - unsigned AsyncThreadsCount, - bool StorePreamblesInMemory, - const clangd::CodeCompleteOptions &CodeCompleteOpts, - clangd::Logger &Logger, - llvm::Optional ResourceDir) +ClangdServer::ClangdServer( + GlobalCompilationDatabase &CDB, DiagnosticsConsumer &DiagConsumer, + FileSystemProvider &FSProvider, unsigned AsyncThreadsCount, + bool StorePreamblesInMemory, + const clangd::CodeCompleteOptions &CodeCompleteOpts, clangd::Logger &Logger, + std::vector> + AdditionalIndexes, + llvm::Optional ResourceDir) : Logger(Logger), CDB(CDB), DiagConsumer(DiagConsumer), - FSProvider(FSProvider), + FSProvider(FSProvider), Units(&IndexSourcer), ResourceDir(ResourceDir ? ResourceDir->str() : getStandardResourceDir()), PCHs(std::make_shared()), StorePreamblesInMemory(StorePreamblesInMemory), - CodeCompleteOpts(CodeCompleteOpts), WorkScheduler(AsyncThreadsCount) {} + CodeCompleteOpts(CodeCompleteOpts), WorkScheduler(AsyncThreadsCount) { + CombinedSymbolIndex::WeightedIndex WeightedASTIndex( + llvm::make_unique(&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( @@ -195,8 +203,9 @@ DocVersion Version = DraftMgr.updateDraft(File, Contents); auto TaggedFS = FSProvider.getTaggedFileSystem(File); - std::shared_ptr Resources = Units.getOrCreateFile( - File, ResourceDir, CDB, StorePreamblesInMemory, PCHs, Logger); + std::shared_ptr Resources = + Units.getOrCreateFile(File, ResourceDir, CDB, StorePreamblesInMemory, + PCHs, Logger, &IndexSourcer); return scheduleReparseAndDiags(File, VersionedDraft{Version, Contents.str()}, std::move(Resources), std::move(TaggedFS)); } @@ -287,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/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" @@ -146,12 +148,14 @@ static std::shared_ptr Create(PathRef FileName, tooling::CompileCommand Command, bool StorePreamblesInMemory, - std::shared_ptr PCHs, clangd::Logger &Logger); + std::shared_ptr PCHs, clangd::Logger &Logger, + ASTIndexSourcer *IndexSourcer); private: CppFile(PathRef FileName, tooling::CompileCommand Command, bool StorePreamblesInMemory, - std::shared_ptr PCHs, clangd::Logger &Logger); + std::shared_ptr PCHs, clangd::Logger &Logger, + ASTIndexSourcer *IndexSourcer); public: CppFile(CppFile const &) = delete; @@ -209,6 +213,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 { @@ -254,6 +260,8 @@ std::shared_ptr PCHs; /// Used for logging various messages. clangd::Logger &Logger; + + ASTIndexSourcer *IndexSourcer; }; struct CodeCompleteOptions { @@ -274,7 +282,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 @@ -291,12 +299,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, - std::shared_ptr PCHs, - clangd::CodeCompleteOptions Opts, clangd::Logger &Logger); +CompletionList codeComplete(PathRef FileName, + const tooling::CompileCommand &Command, + PrecompiledPreamble const *Preamble, + StringRef Contents, Position Pos, + IntrusiveRefCntPtr VFS, + std::shared_ptr 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" @@ -436,17 +437,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()), - CCTUInfo(Allocator) {} + CCTUInfo(Allocator), Index(Index) {} void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, CodeCompletionResult *Results, unsigned NumResults) override final { std::priority_queue Candidates; + if (auto OptSS = Context.getCXXScopeSpecifier()) { + 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) { auto &Result = Results[I]; if (!ClangdOpts.IncludeIneligibleResults && @@ -498,6 +506,77 @@ return Item; } + void doGlobalCompletion(Sema &S, const 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(DC)) { + InferredSpecifier = NS->getQualifiedNameAsString(); + llvm::errs() << " Namespace: " << InferredSpecifier << "\n"; + } else if (auto *TU = llvm::dyn_cast(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 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; @@ -505,7 +584,7 @@ CompletionList &Items; std::shared_ptr Allocator; CodeCompletionTUInfo CCTUInfo; - + const SymbolIndex &Index; }; // CompletionItemsCollector bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) { @@ -519,8 +598,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, @@ -556,8 +635,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, @@ -839,15 +918,16 @@ PrecompiledPreamble const *Preamble, StringRef Contents, Position Pos, IntrusiveRefCntPtr VFS, std::shared_ptr PCHs, - clangd::CodeCompleteOptions Opts, clangd::Logger &Logger) { + clangd::CodeCompleteOptions Opts, clangd::Logger &Logger, + const SymbolIndex &Index) { CompletionList Results; std::unique_ptr Consumer; if (Opts.EnableSnippets) { - Consumer = - llvm::make_unique(Opts, Results); + Consumer = llvm::make_unique(Opts, Results, + Index); } else { - Consumer = - llvm::make_unique(Opts, Results); + Consumer = llvm::make_unique( + Opts, Results, Index); } invokeCodeComplete(std::move(Consumer), Opts.getClangCompleteOpts(), FileName, Command, Preamble, Contents, Pos, std::move(VFS), @@ -1136,19 +1216,23 @@ CppFile::Create(PathRef FileName, tooling::CompileCommand Command, bool StorePreamblesInMemory, std::shared_ptr PCHs, - clangd::Logger &Logger) { - return std::shared_ptr(new CppFile(FileName, std::move(Command), - StorePreamblesInMemory, - std::move(PCHs), Logger)); + clangd::Logger &Logger, ASTIndexSourcer *IndexSourcer) { + return std::shared_ptr( + new CppFile(FileName, std::move(Command), StorePreamblesInMemory, + std::move(PCHs), Logger, IndexSourcer)); } CppFile::CppFile(PathRef FileName, tooling::CompileCommand Command, bool StorePreamblesInMemory, std::shared_ptr 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 Lock(Mutex); LatestAvailablePreamble = nullptr; @@ -1345,6 +1429,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/ClangdUnitStore.h =================================================================== --- clangd/ClangdUnitStore.h +++ clangd/ClangdUnitStore.h @@ -12,6 +12,7 @@ #include +#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 getOrCreateFile(PathRef File, PathRef ResourceDir, GlobalCompilationDatabase &CDB, bool StorePreamblesInMemory, std::shared_ptr PCHs, - clangd::Logger &Logger) { + clangd::Logger &Logger, ASTIndexSourcer *IndexSourcer) { std::lock_guard 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> OpenedFiles; + ASTIndexSourcer *IndexSourcer; }; } // namespace clangd } // namespace clang Index: clangd/ClangdUnitStore.cpp =================================================================== --- clangd/ClangdUnitStore.cpp +++ clangd/ClangdUnitStore.cpp @@ -23,6 +23,7 @@ std::shared_ptr 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/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 FixedPrefixes; +}; + +struct ScoreSignals { + float fuzzy_score; +}; + +struct CompletionSymbol { + ScoreSignals Signals; + + std::string UID; + std::string QualifiedName; +}; + +struct CompletionResult { + //std::vector Symbol; + std::vector Symbols; + bool all_matched; +}; + +class SymbolIndex { +public: + virtual ~SymbolIndex() = default; + + virtual llvm::Expected + complete(const CompletionRequest &Req) const = 0; + + virtual llvm::Expected + getSymbolInfo(llvm::StringRef UID) const = 0; + + virtual llvm::Expected> + getAllOccurrences(llvm::StringRef UID) const = 0; +}; + +} // namespace clangd +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPLETIONINDEX_H Index: clangd/tool/ClangdMain.cpp =================================================================== --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -172,8 +172,7 @@ CCOpts.IncludeIneligibleResults = IncludeIneligibleResults; // Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer(Out, WorkerThreadsCount, StorePreamblesInMemory, - CCOpts, ResourceDirRef, - CompileCommandsDirPath); + CCOpts, ResourceDirRef, CompileCommandsDirPath, {}); constexpr int NoShutdownRequestErrorCode = 1; llvm::set_thread_name("clangd.main"); return LSPServer.run(std::cin) ? 0 : NoShutdownRequestErrorCode;