Index: clangd/ClangdServer.h =================================================================== --- clangd/ClangdServer.h +++ clangd/ClangdServer.h @@ -99,6 +99,7 @@ /// synchronize access to shared state. ClangdServer(GlobalCompilationDatabase &CDB, FileSystemProvider &FSProvider, DiagnosticsConsumer &DiagConsumer, const Options &Opts); + ~ClangdServer(); /// Set the root path of the workspace. void setRootPath(PathRef RootPath); @@ -200,6 +201,7 @@ formatCode(llvm::StringRef Code, PathRef File, ArrayRef Ranges); + class DynamicIndex; typedef uint64_t DocVersion; void consumeDiagnostics(PathRef File, DocVersion Version, @@ -217,15 +219,14 @@ Path ResourceDir; // The index used to look up symbols. This could be: // - null (all index functionality is optional) - // - the dynamic index owned by ClangdServer (FileIdx) + // - the dynamic index owned by ClangdServer (DynamicIdx) // - 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, a merged view of FileIdx and an external index. Read via Index. + /// If present, an up-to-date of symbols in open files. Read via Index. + std::unique_ptr DynamicIdx; + // If present, a merged view of DynamicIdx and an external index. Read via + // Index. std::unique_ptr MergedIndex; // If set, this represents the workspace path. llvm::Optional RootPath; Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -65,27 +65,39 @@ Optional> Result; }; +} // namespace -class UpdateFileIndex : public ParsingCallbacks { +/// 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 ClangdServer::DynamicIndex : public ParsingCallbacks { public: - UpdateFileIndex(FileIndex *FileIdx) : FileIdx(FileIdx) {} + DynamicIndex(std::vector URISchemes) + : PreambleIdx(URISchemes), MainFileIdx(URISchemes), + MergedIndex(mergeIndex(&MainFileIdx, &PreambleIdx)) {} + + SymbolIndex &index() const { return *MergedIndex; } void onPreambleAST(PathRef Path, ASTContext &Ctx, std::shared_ptr PP) override { - if (FileIdx) - FileIdx->update(Path, &Ctx, std::move(PP)); + PreambleIdx.update(Path, &Ctx, PP, /*TopLevelDecls=*/llvm::None); } void onMainAST(PathRef Path, ParsedAST &AST) override { - // FIXME: merge results from the main file into the index too. + + MainFileIdx.update(Path, &AST.getASTContext(), AST.getPreprocessorPtr(), + AST.getLocalTopLevelDecls()); } private: - FileIndex *FileIdx; + 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; }; -} // namespace - ClangdServer::Options ClangdServer::optsForTest() { ClangdServer::Options Opts; Opts.UpdateDebounce = std::chrono::steady_clock::duration::zero(); // Faster! @@ -101,9 +113,9 @@ : CDB(CDB), DiagConsumer(DiagConsumer), FSProvider(FSProvider), ResourceDir(Opts.ResourceDir ? Opts.ResourceDir->str() : getStandardResourceDir()), - FileIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex(Opts.URISchemes) - : nullptr), - FileIdxUpdater(llvm::make_unique(FileIdx.get())), + DynamicIdx(Opts.BuildDynamicSymbolIndex + ? new DynamicIndex(Opts.URISchemes) + : nullptr), 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,19 +123,23 @@ // 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) { - if (FileIdx && Opts.StaticIndex) { - MergedIndex = mergeIndex(FileIdx.get(), Opts.StaticIndex); + DynamicIdx ? *DynamicIdx : noopParsingCallbacks(), + Opts.UpdateDebounce, Opts.RetentionPolicy) { + if (DynamicIdx && Opts.StaticIndex) { + MergedIndex = mergeIndex(&DynamicIdx->index(), Opts.StaticIndex); Index = MergedIndex.get(); - } else if (FileIdx) - Index = FileIdx.get(); + } else if (DynamicIdx) + Index = &DynamicIdx->index(); else if (Opts.StaticIndex) Index = Opts.StaticIndex; else Index = nullptr; } +// Destructor has to be in .cpp file to see the definition of +// ClangdServer::DynamicIndex. +ClangdServer::~ClangdServer() = default; + void ClangdServer::setRootPath(PathRef RootPath) { auto FS = FSProvider.getFileSystem(); auto Status = FS->status(RootPath); 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,14 @@ 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 DeclsToIndex; + if (TopLevelDecls) + DeclsToIndex.assign(TopLevelDecls->begin(), TopLevelDecls->end()); + else + DeclsToIndex.assign(AST.getTranslationUnitDecl()->decls().begin(), + AST.getTranslationUnitDecl()->decls().end()); + + index::indexTopLevelDecls(AST, DeclsToIndex, Collector, IndexOpts); return Collector.takeSymbols(); } @@ -81,13 +86,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();