Index: clangd/ClangdServer.h =================================================================== --- clangd/ClangdServer.h +++ clangd/ClangdServer.h @@ -207,6 +207,27 @@ tooling::CompileCommand getCompileCommand(PathRef File); + /// Manages dynamic index for open files. Each file might contribute two sets + /// of symbols to the dynamic index: symbols from the preamble and symbols + /// from the file itself. Those have different lifetimes and we merge results from both + class DynamicIndex : public ParsingCallbacks { + public: + DynamicIndex(std::vector URISchemes); + + SymbolIndex &index() const; + + void onPreambleAST(PathRef Path, ASTContext &Ctx, + std::shared_ptr PP) override; + void onMainAST(PathRef Path, ParsedAST &AST) override; + + private: + FileIndex PreambleIdx; + FileIndex MainFileIdx; + /// Merged view into both indexes. Merges are performed in a similar manner + /// to the merges of dynamic and static index. + std::unique_ptr MergedIndex; + }; + GlobalCompilationDatabase &CDB; DiagnosticsConsumer &DiagConsumer; FileSystemProvider &FSProvider; @@ -221,10 +242,8 @@ // - the static index passed to the constructor // - a merged view of a static and dynamic index (MergedIndex) SymbolIndex *Index; - // If present, an up-to-date of symbols in open files. Read via Index. - std::unique_ptr FileIdx; - /// Callbacks responsible for updating FileIdx. - std::unique_ptr FileIdxUpdater; + /// If present, an up-to-date of symbols in open files. Read via Index. + std::unique_ptr FileIdx; // If present, a merged view of FileIdx and an external index. Read via Index. std::unique_ptr MergedIndex; // If set, this represents the workspace path. Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -66,22 +66,17 @@ Optional> Result; }; -class UpdateFileIndex : public ParsingCallbacks { +// FIXME(ibiryukov): this should be a generic helper instead. +class NoopCallbacks : public ParsingCallbacks { public: - UpdateFileIndex(FileIndex *FileIdx) : FileIdx(FileIdx) {} - - void onPreambleAST(PathRef Path, ASTContext &Ctx, - std::shared_ptr PP) override { - if (FileIdx) - FileIdx->update(Path, &Ctx, std::move(PP)); - } - - void onMainAST(PathRef Path, ParsedAST &AST) override { - // FIXME: merge results from the main file into the index too. + static ParsingCallbacks &instance() { + static ParsingCallbacks *Instance = new NoopCallbacks; + return *Instance; } -private: - FileIndex *FileIdx; + void onPreambleAST(PathRef Path, ASTContext &Ctx, + std::shared_ptr PP) override {} + void onMainAST(PathRef Path, ParsedAST &AST) override {} }; } // namespace @@ -101,9 +96,8 @@ : CDB(CDB), DiagConsumer(DiagConsumer), FSProvider(FSProvider), ResourceDir(Opts.ResourceDir ? Opts.ResourceDir->str() : getStandardResourceDir()), - FileIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex(Opts.URISchemes) + FileIdx(Opts.BuildDynamicSymbolIndex ? new DynamicIndex(Opts.URISchemes) : nullptr), - FileIdxUpdater(llvm::make_unique(FileIdx.get())), PCHs(std::make_shared()), // Pass a callback into `WorkScheduler` to extract symbols from a newly // parsed file and rebuild the file index synchronously each time an AST @@ -111,13 +105,13 @@ // FIXME(ioeric): this can be slow and we may be able to index on less // critical paths. WorkScheduler(Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory, - *FileIdxUpdater, Opts.UpdateDebounce, - Opts.RetentionPolicy) { + FileIdx ? *FileIdx : NoopCallbacks::instance(), + Opts.UpdateDebounce, Opts.RetentionPolicy) { if (FileIdx && Opts.StaticIndex) { - MergedIndex = mergeIndex(FileIdx.get(), Opts.StaticIndex); + MergedIndex = mergeIndex(&FileIdx->index(), Opts.StaticIndex); Index = MergedIndex.get(); } else if (FileIdx) - Index = FileIdx.get(); + Index = &FileIdx->index(); else if (Opts.StaticIndex) Index = Opts.StaticIndex; else @@ -488,3 +482,19 @@ ClangdServer::blockUntilIdleForTest(llvm::Optional TimeoutSeconds) { return WorkScheduler.blockUntilIdle(timeoutSeconds(TimeoutSeconds)); } + +ClangdServer::DynamicIndex::DynamicIndex(std::vector URISchemes) + : PreambleIdx(URISchemes), MainFileIdx(URISchemes), + MergedIndex(mergeIndex(&MainFileIdx, &PreambleIdx)) {} + +SymbolIndex &ClangdServer::DynamicIndex::index() const { return *MergedIndex; } + +void ClangdServer::DynamicIndex::onPreambleAST( + PathRef Path, ASTContext &Ctx, std::shared_ptr PP) { + PreambleIdx.update(Path, &Ctx, PP, /*TopLevelDecls=*/llvm::None); +} + +void ClangdServer::DynamicIndex::onMainAST(PathRef Path, ParsedAST &AST) { + MainFileIdx.update(Path, &AST.getASTContext(), AST.getPreprocessorPtr(), + AST.getLocalTopLevelDecls()); +} Index: clangd/index/FileIndex.h =================================================================== --- clangd/index/FileIndex.h +++ clangd/index/FileIndex.h @@ -64,7 +64,11 @@ /// nullptr, this removes all symbols in the file. /// If \p AST is not null, \p PP cannot be null and it should be the /// preprocessor that was used to build \p AST. - void update(PathRef Path, ASTContext *AST, std::shared_ptr PP); + /// If \p TopLevelDecls is set, only these decls are indexed. Otherwise, all + /// top level decls obtained from \p AST are indexed. + void + update(PathRef Path, ASTContext *AST, std::shared_ptr PP, + llvm::Optional> TopLevelDecls = llvm::None); bool fuzzyFind(const FuzzyFindRequest &Req, @@ -86,8 +90,12 @@ /// Retrieves namespace and class level symbols in \p AST. /// Exposed to assist in unit tests. /// If URISchemes is empty, the default schemes in SymbolCollector will be used. -SymbolSlab indexAST(ASTContext &AST, std::shared_ptr PP, - llvm::ArrayRef URISchemes = {}); +/// If \p TopLevelDecls is set, only these decls are indexed. Otherwise, all top +/// level decls obtained from \p AST are indexed. +SymbolSlab +indexAST(ASTContext &AST, std::shared_ptr PP, + llvm::Optional> TopLevelDecls = llvm::None, + llvm::ArrayRef URISchemes = {}); } // namespace clangd } // namespace clang Index: clangd/index/FileIndex.cpp =================================================================== --- clangd/index/FileIndex.cpp +++ clangd/index/FileIndex.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include "FileIndex.h" -#include "SymbolCollector.h" #include "../Logger.h" +#include "SymbolCollector.h" #include "clang/Index/IndexingAction.h" #include "clang/Lex/Preprocessor.h" @@ -17,6 +17,7 @@ namespace clangd { SymbolSlab indexAST(ASTContext &AST, std::shared_ptr PP, + llvm::Optional> TopLevelDecls, llvm::ArrayRef URISchemes) { SymbolCollector::Options CollectorOpts; // FIXME(ioeric): we might also want to collect include headers. We would need @@ -38,10 +39,13 @@ index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly; IndexOpts.IndexFunctionLocals = false; - std::vector TopLevelDecls( - AST.getTranslationUnitDecl()->decls().begin(), - AST.getTranslationUnitDecl()->decls().end()); - index::indexTopLevelDecls(AST, TopLevelDecls, Collector, IndexOpts); + std::vector Storage; + if (!TopLevelDecls) { + Storage.assign(AST.getTranslationUnitDecl()->decls().begin(), + AST.getTranslationUnitDecl()->decls().end()); + TopLevelDecls = Storage; + } + index::indexTopLevelDecls(AST, *TopLevelDecls, Collector, IndexOpts); return Collector.takeSymbols(); } @@ -81,13 +85,14 @@ } void FileIndex::update(PathRef Path, ASTContext *AST, - std::shared_ptr PP) { + std::shared_ptr PP, + llvm::Optional> TopLevelDecls) { if (!AST) { FSymbols.update(Path, nullptr); } else { assert(PP); auto Slab = llvm::make_unique(); - *Slab = indexAST(*AST, PP, URISchemes); + *Slab = indexAST(*AST, PP, TopLevelDecls, URISchemes); FSymbols.update(Path, std::move(Slab)); } auto Symbols = FSymbols.allSymbols();