diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -166,6 +166,9 @@ /// Enable preview of FoldingRanges feature. bool FoldingRanges = false; + /// Prebuild ASTs for files in the compilation database. + bool PrebuildASTs = false; + explicit operator TUScheduler::Options() const; }; // Sensible default options for use in tests. @@ -357,6 +360,7 @@ Context createProcessingContext(PathRef) const; config::Provider *ConfigProvider = nullptr; + const GlobalCompilationDatabase &CDB; const ThreadsafeFS &TFS; Path ResourceDir; @@ -384,6 +388,8 @@ bool BuildRecoveryAST = true; // If true, preserve the type for recovery AST. bool PreserveRecoveryASTType = false; + // If true, prebuild ASTs for all files in a compilation database. + bool PrebuildASTs = false; // GUARDED_BY(CachedCompletionFuzzyFindRequestMutex) llvm::StringMap> diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -172,7 +172,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS, const Options &Opts, Callbacks *Callbacks) - : ConfigProvider(Opts.ConfigProvider), TFS(TFS), + : ConfigProvider(Opts.ConfigProvider), CDB(CDB), TFS(TFS), DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex(Opts.HeavyweightDynamicSymbolIndex, Opts.CollectMainFileRefs) @@ -181,7 +181,7 @@ SuggestMissingIncludes(Opts.SuggestMissingIncludes), BuildRecoveryAST(Opts.BuildRecoveryAST), PreserveRecoveryASTType(Opts.PreserveRecoveryASTType), - WorkspaceRoot(Opts.WorkspaceRoot), + PrebuildASTs(Opts.PrebuildASTs), WorkspaceRoot(Opts.WorkspaceRoot), // Pass a callback into `WorkScheduler` to extract symbols from a newly // parsed file and rebuild the file index synchronously each time an AST // is parsed. @@ -257,7 +257,7 @@ Inputs.Contents = std::string(Contents); Inputs.Version = Version.str(); Inputs.ForceRebuild = ForceRebuild; - Inputs.Opts = std::move(Opts); + Inputs.Opts = Opts; Inputs.Index = Index; Inputs.Opts.BuildRecoveryAST = BuildRecoveryAST; Inputs.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType; @@ -265,6 +265,23 @@ // If we loaded Foo.h, we want to make sure Foo.cpp is indexed. if (NewFile && BackgroundIdx) BackgroundIdx->boostRelated(File); + + // If --prebuild-asts is enabled, loop over all the files in the compilation + // database and schedule an AST update for them if they haven't yet been added + // to the WorkScheduler before. + if (NewFile && PrebuildASTs) { + if (auto *InternalCDB = CDB.lookupCDB(File)) { + for (const auto &CDBFile : InternalCDB->getAllFiles()) { + if (CDBFile != File && !WorkScheduler.hasFile(File)) { + auto Buffer = llvm::MemoryBuffer::getFile(File); + Inputs.Contents = std::string(Buffer->get()->getBuffer()); + WorkScheduler.update(CDBFile, Inputs, WantDiagnostics::No); + if (BackgroundIdx) + BackgroundIdx->boostRelated(CDBFile); + } + } + } + } } void ClangdServer::removeDocument(PathRef File) { WorkScheduler.remove(File); } diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/clang-tools-extra/clangd/GlobalCompilationDatabase.h --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h @@ -40,6 +40,8 @@ virtual llvm::Optional getCompileCommand(PathRef File) const = 0; + virtual tooling::CompilationDatabase *lookupCDB(PathRef File) const = 0; + /// Finds the closest project to \p File. virtual llvm::Optional getProjectInfo(PathRef File) const { return llvm::None; @@ -76,6 +78,8 @@ llvm::Optional getCompileCommand(PathRef File) const override; + virtual tooling::CompilationDatabase *lookupCDB(PathRef File) const override; + /// Returns the path to first directory containing a compilation database in /// \p File's parents. llvm::Optional getProjectInfo(PathRef File) const override; @@ -132,6 +136,9 @@ llvm::Optional getCompileCommand(PathRef File) const override; + + tooling::CompilationDatabase *lookupCDB(PathRef File) const override; + tooling::CompileCommand getFallbackCommand(PathRef File) const override; /// Project info is gathered purely from the inner compilation database to /// ensure consistency. diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp @@ -68,6 +68,20 @@ llvm::Optional DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const { + auto *CDB = lookupCDB(File); + if (!CDB) { + return llvm::None; + } + + auto Candidates = CDB->getCompileCommands(File); + if (!Candidates.empty()) + return std::move(Candidates.front()); + + return None; +} + +tooling::CompilationDatabase * +DirectoryBasedGlobalCompilationDatabase::lookupCDB(PathRef File) const { CDBLookupRequest Req; Req.FileName = File; Req.ShouldBroadcast = true; @@ -75,14 +89,10 @@ auto Res = lookupCDB(Req); if (!Res) { log("Failed to find compilation database for {0}", File); - return llvm::None; + return nullptr; } - auto Candidates = Res->CDB->getCompileCommands(File); - if (!Candidates.empty()) - return std::move(Candidates.front()); - - return None; + return Res->CDB; } // For platforms where paths are case-insensitive (but case-preserving), @@ -270,6 +280,10 @@ return Cmd; } +tooling::CompilationDatabase *OverlayCDB::lookupCDB(PathRef File) const { + return Base ? Base->lookupCDB(File) : nullptr; +} + tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const { auto Cmd = Base ? Base->getFallbackCommand(File) : GlobalCompilationDatabase::getFallbackCommand(File); diff --git a/clang-tools-extra/clangd/QueryDriverDatabase.cpp b/clang-tools-extra/clangd/QueryDriverDatabase.cpp --- a/clang-tools-extra/clangd/QueryDriverDatabase.cpp +++ b/clang-tools-extra/clangd/QueryDriverDatabase.cpp @@ -277,6 +277,10 @@ return addSystemIncludes(*Cmd, SystemIncludes); } + tooling::CompilationDatabase *lookupCDB(PathRef File) const override { + return Base->lookupCDB(File); + } + llvm::Optional getProjectInfo(PathRef File) const override { return Base->getProjectInfo(File); } diff --git a/clang-tools-extra/clangd/TUScheduler.h b/clang-tools-extra/clangd/TUScheduler.h --- a/clang-tools-extra/clangd/TUScheduler.h +++ b/clang-tools-extra/clangd/TUScheduler.h @@ -231,6 +231,8 @@ /// Returns true if the file was not previously tracked. bool update(PathRef File, ParseInputs Inputs, WantDiagnostics WD); + bool hasFile(PathRef File); + /// Remove \p File from the list of tracked files and schedule removal of its /// resources. Pending diagnostics for closed files may not be delivered, even /// if requested with WantDiags::Auto or WantDiags::Yes. diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -1289,6 +1289,8 @@ return NewFile; } +bool TUScheduler::hasFile(PathRef File) { return Files[File] == nullptr; } + void TUScheduler::remove(PathRef File) { bool Removed = Files.erase(File); if (!Removed) diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -492,6 +492,13 @@ init(false), }; +opt PrebuildASTs{ + "prebuild-asts", + cat(Misc), + desc("Prebuild ASTs for all files in the compilation database"), + init(false), +}; + #if CLANGD_ENABLE_REMOTE opt RemoteIndexAddress{ "remote-index-address", @@ -848,6 +855,7 @@ // Shall we allow to customize the file limit? Opts.Rename.AllowCrossFile = CrossFileRename; + Opts.PrebuildASTs = PrebuildASTs; if (CheckFile.getNumOccurrences()) { llvm::SmallString<256> Path;