Index: clangd/ClangdServer.h =================================================================== --- clangd/ClangdServer.h +++ clangd/ClangdServer.h @@ -331,13 +331,30 @@ std::future scheduleReparseAndDiags(Context Ctx, PathRef File, VersionedDraft Contents, std::shared_ptr Resources, - Tagged> TaggedFS, - bool AllowCachedCompileFlags); + Tagged> TaggedFS); std::future scheduleCancelRebuild(Context Ctx, std::shared_ptr Resources); - GlobalCompilationDatabase &CDB; + // Stores compile commands produced by GlobalCompilationDatabase. + class CompileArgsCache { + public: + CompileArgsCache(GlobalCompilationDatabase &CDB, Path ResourceDir); + + /// Gets compile command for \p File from cache or CDB if it's not in the + /// cache. + tooling::CompileCommand getCompileCommand(PathRef File); + + /// Removes a cache entry for \p File, if it's present in the cache. + void invalidate(PathRef File); + + private: + GlobalCompilationDatabase &CDB; + const Path ResourceDir; + llvm::StringMap Cached; + }; + + CompileArgsCache CompileArgs; DiagnosticsConsumer &DiagConsumer; FileSystemProvider &FSProvider; DraftStore DraftMgr; @@ -352,7 +369,6 @@ // If present, a merged view of FileIdx and an external index. Read via Index. std::unique_ptr MergedIndex; CppFileCollection Units; - std::string ResourceDir; // If set, this represents the workspace path. llvm::Optional RootPath; std::shared_ptr PCHs; Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -149,7 +149,9 @@ bool StorePreamblesInMemory, bool BuildDynamicSymbolIndex, SymbolIndex *StaticIdx, llvm::Optional ResourceDir) - : CDB(CDB), DiagConsumer(DiagConsumer), FSProvider(FSProvider), + : CompileArgs(CDB, + ResourceDir ? ResourceDir->str() : getStandardResourceDir()), + DiagConsumer(DiagConsumer), FSProvider(FSProvider), FileIdx(BuildDynamicSymbolIndex ? new FileIndex() : nullptr), // Pass a callback into `Units` to extract symbols from a newly parsed // file and rebuild the file index synchronously each time an AST is @@ -160,7 +162,6 @@ ? [this](const Context &Ctx, PathRef Path, ParsedAST *AST) { FileIdx->update(Ctx, Path, AST); } : ASTParsedCallback()), - ResourceDir(ResourceDir ? ResourceDir->str() : getStandardResourceDir()), PCHs(std::make_shared()), StorePreamblesInMemory(StorePreamblesInMemory), WorkScheduler(AsyncThreadsCount) { @@ -188,15 +189,16 @@ auto TaggedFS = FSProvider.getTaggedFileSystem(File); std::shared_ptr Resources = - Units.getOrCreateFile(File, ResourceDir, StorePreamblesInMemory, PCHs); + Units.getOrCreateFile(File, StorePreamblesInMemory, PCHs); return scheduleReparseAndDiags(std::move(Ctx), File, VersionedDraft{Version, Contents.str()}, - std::move(Resources), std::move(TaggedFS), - /*AllowCachedCompileFlags=*/true); + std::move(Resources), std::move(TaggedFS)); } std::future ClangdServer::removeDocument(Context Ctx, PathRef File) { DraftMgr.removeDraft(File); + CompileArgs.invalidate(File); + std::shared_ptr Resources = Units.removeIfPresent(File); return scheduleCancelRebuild(std::move(Ctx), std::move(Resources)); } @@ -206,12 +208,15 @@ assert(FileContents.Draft && "forceReparse() was called for non-added document"); + // Clear the cached CompileCommand for File, this ensures the new one will be + // requested for the next reparse. + CompileArgs.invalidate(File); + auto TaggedFS = FSProvider.getTaggedFileSystem(File); std::shared_ptr Resources = - Units.getOrCreateFile(File, ResourceDir, StorePreamblesInMemory, PCHs); + Units.getOrCreateFile(File, StorePreamblesInMemory, PCHs); return scheduleReparseAndDiags(std::move(Ctx), File, FileContents, - std::move(Resources), std::move(TaggedFS), - /*AllowCachedCompileFlags=*/false); + std::move(Resources), std::move(TaggedFS)); } std::future>> @@ -278,9 +283,7 @@ // Copy PCHs to avoid accessing this->PCHs concurrently std::shared_ptr PCHs = this->PCHs; - assert(Resources->getLastCommand() && - "CppFile is in inconsistent state, missing CompileCommand"); - tooling::CompileCommand CompileCommand = *Resources->getLastCommand(); + tooling::CompileCommand CompileCommand = CompileArgs.getCompileCommand(File); // A task that will be run asynchronously. auto Task = @@ -332,12 +335,9 @@ "signatureHelp is called for non-added document", llvm::errc::invalid_argument); - assert(Resources->getLastCommand() && - "CppFile is in inconsistent state, missing CompileCommand"); - auto Preamble = Resources->getPossiblyStalePreamble(); auto Result = - clangd::signatureHelp(Ctx, File, *Resources->getLastCommand(), + clangd::signatureHelp(Ctx, File, CompileArgs.getCompileCommand(File), Preamble ? &Preamble->Preamble : nullptr, *OverridenContents, Pos, TaggedFS.Value, PCHs); return make_tagged(std::move(Result), TaggedFS.Tag); @@ -571,18 +571,11 @@ std::future ClangdServer::scheduleReparseAndDiags( Context Ctx, PathRef File, VersionedDraft Contents, std::shared_ptr Resources, - Tagged> TaggedFS, - bool AllowCachedCompileFlags) { - llvm::Optional ReusedCommand; - if (AllowCachedCompileFlags) - ReusedCommand = Resources->getLastCommand(); - tooling::CompileCommand Command = - ReusedCommand ? std::move(*ReusedCommand) - : getCompileCommand(CDB, File, ResourceDir); - - ParseInputs Inputs = {std::move(Command), std::move(TaggedFS.Value), - *std::move(Contents.Draft)}; + Tagged> TaggedFS) { assert(Contents.Draft && "Draft must have contents"); + ParseInputs Inputs = {CompileArgs.getCompileCommand(File), + std::move(TaggedFS.Value), *std::move(Contents.Draft)}; + UniqueFunction>(const Context &)> DeferredRebuild = Resources->deferRebuild(std::move(Inputs)); std::promise DonePromise; @@ -656,3 +649,23 @@ // FIXME: Do nothing for now. This will be used for indexing and potentially // invalidating other caches. } + +ClangdServer::CompileArgsCache::CompileArgsCache(GlobalCompilationDatabase &CDB, + Path ResourceDir) + : CDB(CDB), ResourceDir(std::move(ResourceDir)) {} + +/// Gets compile command for \p File from cache or CDB. +tooling::CompileCommand +ClangdServer::CompileArgsCache::getCompileCommand(PathRef File) { + auto It = Cached.find(File); + if (It == Cached.end()) { + It = Cached.insert({File, ::getCompileCommand(CDB, File, ResourceDir)}) + .first; + } + return It->second; +} + +/// Removes a cache entry for \p File, if it's present in the cache. +void ClangdServer::CompileArgsCache::invalidate(PathRef File) { + Cached.erase(File); +} Index: clangd/ClangdUnit.h =================================================================== --- clangd/ClangdUnit.h +++ clangd/ClangdUnit.h @@ -216,14 +216,6 @@ /// always be non-null. std::shared_future> getAST() const; - /// Get the latest CompileCommand used to build this CppFile. Returns - /// llvm::None before first call to rebuild() or after calls to - /// cancelRebuild(). - // In practice we always call rebuild() when adding a CppFile to the - // CppFileCollection, and only `cancelRebuild()` after removing it. This means - // files in the CppFileCollection always have a compile command available. - llvm::Optional getLastCommand() const; - private: /// A helper guard that manages the state of CppFile during rebuild. class RebuildGuard { @@ -251,7 +243,6 @@ bool RebuildInProgress; /// Condition variable to indicate changes to RebuildInProgress. std::condition_variable RebuildCond; - llvm::Optional LastCommand; /// Promise and future for the latests AST. Fulfilled during rebuild. /// We use std::shared_ptr here because MVSC fails to compile non-copyable Index: clangd/ClangdUnit.cpp =================================================================== --- clangd/ClangdUnit.cpp +++ clangd/ClangdUnit.cpp @@ -455,7 +455,6 @@ this->ASTPromise = std::promise>(); this->ASTFuture = this->ASTPromise.get_future(); } - this->LastCommand = Inputs.CompileCommand; } // unlock Mutex. // Notify about changes to RebuildCounter. RebuildCond.notify_all(); @@ -636,11 +635,6 @@ return ASTFuture; } -llvm::Optional CppFile::getLastCommand() const { - std::lock_guard Lock(Mutex); - return LastCommand; -} - CppFile::RebuildGuard::RebuildGuard(CppFile &File, unsigned RequestRebuildCounter) : File(File), RequestRebuildCounter(RequestRebuildCounter) { Index: clangd/ClangdUnitStore.h =================================================================== --- clangd/ClangdUnitStore.h +++ clangd/ClangdUnitStore.h @@ -31,8 +31,7 @@ : ASTCallback(std::move(ASTCallback)) {} std::shared_ptr - getOrCreateFile(PathRef File, PathRef ResourceDir, - bool StorePreamblesInMemory, + getOrCreateFile(PathRef File, bool StorePreamblesInMemory, std::shared_ptr PCHs) { std::lock_guard Lock(Mutex); auto It = OpenedFiles.find(File);