Index: clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp =================================================================== --- clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp +++ clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp @@ -17,15 +17,15 @@ #include "index/SymbolCollector.h" #include "index/SymbolYAML.h" #include "clang/Frontend/FrontendActions.h" -#include "clang/Index/IndexingAction.h" #include "clang/Index/IndexDataConsumer.h" +#include "clang/Index/IndexingAction.h" #include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Execution.h" #include "clang/Tooling/Tooling.h" -#include "clang/Tooling/CommonOptionsParser.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/Path.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/ThreadPool.h" using namespace llvm; @@ -37,18 +37,20 @@ class SymbolIndexActionFactory : public tooling::FrontendActionFactory { public: - SymbolIndexActionFactory() = default; + SymbolIndexActionFactory(tooling::ExecutionContext *Ctx) : Ctx(Ctx) {} clang::FrontendAction *create() override { index::IndexingOptions IndexOpts; IndexOpts.SystemSymbolFilter = index::IndexingOptions::SystemSymbolFilterKind::All; IndexOpts.IndexFunctionLocals = false; - Collector = std::make_shared(); - return index::createIndexingAction(Collector, IndexOpts, nullptr).release(); + return index::createIndexingAction(std::make_shared(Ctx), + IndexOpts, nullptr) + .release(); } std::shared_ptr Collector; + tooling::ExecutionContext *Ctx; }; } // namespace clangd @@ -61,50 +63,22 @@ "This is an **experimental** tool to generate YAML-format " "project-wide symbols for clangd (global code completion). It would be " "changed and deprecated eventually. Don't use it in production code!"; - CommonOptionsParser OptionsParser(argc, argv, cl::GeneralCategory, - /*Overview=*/Overview); + auto Executor = clang::tooling::createExecutorFromCommandLineArgs( + argc, argv, cl::GeneralCategory, Overview); - // No compilation database found, fallback to single TU analysis, this is - // mainly for debugging purpose: - // global-symbol-buidler /tmp/t.cc -- -std=c++11. - if (OptionsParser.getCompilations().getAllFiles().empty()) { - llvm::errs() << "No compilation database found, processing individual " - "files with flags from command-line\n."; - ClangTool Tool(OptionsParser.getCompilations(), - OptionsParser.getSourcePathList()); - clang::clangd::SymbolIndexActionFactory IndexAction; - Tool.run(&IndexAction); - llvm::outs() << SymbolToYAML(IndexAction.Collector->takeSymbols()); - return 0; + if (!Executor) { + llvm::errs() << llvm::toString(Executor.takeError()) << "\n"; + return 1; } - // Found compilation database, we iterate all TUs from database to get all - // symbols, and then merge them into a single SymbolSlab. - SymbolSlab::Builder GlobalSymbols; - std::mutex SymbolMutex; - auto AddSymbols = [&](const SymbolSlab& NewSymbols) { - // Synchronize set accesses. - std::unique_lock LockGuard(SymbolMutex); - for (auto Sym : NewSymbols) { - // FIXME: Better handling the overlap symbols, currently we overwrite it - // with the latest one, but we always want to good declarations (class - // definitions, instead of forward declarations). - GlobalSymbols.insert(Sym); - } - }; - - { - llvm::ThreadPool Pool; - for (auto& file : OptionsParser.getCompilations().getAllFiles()) { - Pool.async([&OptionsParser, &AddSymbols](llvm::StringRef Path) { - ClangTool Tool(OptionsParser.getCompilations(), {Path}); - clang::clangd::SymbolIndexActionFactory IndexAction; - Tool.run(&IndexAction); - AddSymbols(IndexAction.Collector->takeSymbols()); - }, file); - } + auto Err = Executor->get()->execute( + llvm::make_unique( + Executor->get()->getExecutionContext())); + if (Err) { + llvm::errs() << llvm::toString(std::move(Err)) << "\n"; } - llvm::outs() << SymbolToYAML(std::move(GlobalSymbols).build()); + Executor->get()->getToolResults()->forEachResult( + [](llvm::StringRef, llvm::StringRef Value) { llvm::outs() << Value; }); return 0; } Index: clangd/index/SymbolCollector.h =================================================================== --- clangd/index/SymbolCollector.h +++ clangd/index/SymbolCollector.h @@ -10,18 +10,23 @@ #include "Index.h" #include "clang/Index/IndexDataConsumer.h" #include "clang/Index/IndexSymbol.h" +#include "clang/Tooling/Execution.h" namespace clang { namespace clangd { -// Collect all symbols from an AST. -// -// Clients (e.g. clangd) can use SymbolCollector together with -// index::indexTopLevelDecls to retrieve all symbols when the source file is -// changed. +/// \brief Collect all symbols from an AST. +/// +/// Clients (e.g. clangd) can use SymbolCollector together with +/// index::indexTopLevelDecls to retrieve all symbols when the source file is +/// changed. class SymbolCollector : public index::IndexDataConsumer { public: - SymbolCollector() = default; + /// \brief If Context is provided, collected symbols will also be reported via + /// the execution context with symbol IDs as keys and yamlized symbols as + /// values. + SymbolCollector(tooling::ExecutionContext *Context = nullptr) + : ExecutionCtx(Context) {} bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles, @@ -34,6 +39,7 @@ private: // All Symbols collected from the AST. SymbolSlab::Builder Symbols; + tooling::ExecutionContext *ExecutionCtx; }; } // namespace clangd Index: clangd/index/SymbolCollector.cpp =================================================================== --- clangd/index/SymbolCollector.cpp +++ clangd/index/SymbolCollector.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "SymbolCollector.h" +#include "index/SymbolYAML.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -106,6 +107,12 @@ S.Name = ScopeAndName.second; S.SymInfo = index::getSymbolInfo(D); S.CanonicalDeclaration = Location; + if (ExecutionCtx) { + std::string IDStr; + llvm::raw_string_ostream OS(IDStr); + OS << S.ID; + ExecutionCtx->reportResult(OS.str(), SymbolToYAML(S)); + } Symbols.insert(S); } Index: clangd/index/SymbolYAML.h =================================================================== --- clangd/index/SymbolYAML.h +++ clangd/index/SymbolYAML.h @@ -27,9 +27,13 @@ // Read symbols from a YAML-format string. SymbolSlab SymbolFromYAML(llvm::StringRef YAMLContent); +// Convert a single symbol to YAML-format string. +// The YAML result is safe to concatenate. +std::string SymbolToYAML(Symbol Sym); + // Convert symbols to a YAML-format string. // The YAML result is safe to concatenate if you have multiple symbol slabs. -std::string SymbolToYAML(const SymbolSlab& Symbols); +std::string SymbolsToYAML(const SymbolSlab& Symbols); } // namespace clangd } // namespace clang Index: clangd/index/SymbolYAML.cpp =================================================================== --- clangd/index/SymbolYAML.cpp +++ clangd/index/SymbolYAML.cpp @@ -133,7 +133,7 @@ return std::move(Syms).build(); } -std::string SymbolToYAML(const SymbolSlab& Symbols) { +std::string SymbolsToYAML(const SymbolSlab& Symbols) { std::string Str; llvm::raw_string_ostream OS(Str); llvm::yaml::Output Yout(OS); @@ -142,5 +142,13 @@ return OS.str(); } +std::string SymbolToYAML(Symbol Sym) { + std::string Str; + llvm::raw_string_ostream OS(Str); + llvm::yaml::Output Yout(OS); + Yout << Sym; + return OS.str(); +} + } // namespace clangd } // namespace clang Index: unittests/clangd/SymbolCollectorTests.cpp =================================================================== --- unittests/clangd/SymbolCollectorTests.cpp +++ unittests/clangd/SymbolCollectorTests.cpp @@ -147,7 +147,7 @@ UnorderedElementsAre(QName("clang::Foo2"))); std::string ConcatenatedYAML = - SymbolToYAML(Symbols1) + SymbolToYAML(Symbols2); + SymbolsToYAML(Symbols1) + SymbolsToYAML(Symbols2); auto ConcatenatedSymbols = SymbolFromYAML(ConcatenatedYAML); EXPECT_THAT(ConcatenatedSymbols, UnorderedElementsAre(QName("clang::Foo1"),