Index: clangd/CMakeLists.txt =================================================================== --- clangd/CMakeLists.txt +++ clangd/CMakeLists.txt @@ -47,3 +47,4 @@ add_subdirectory(fuzzer) endif() add_subdirectory(tool) +add_subdirectory(global-symbol-builder) Index: clangd/global-symbol-builder/CMakeLists.txt =================================================================== --- /dev/null +++ clangd/global-symbol-builder/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../) + +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_executable(global-symbol-builder + GlobalSymbolBuilderMain.cpp + ) + +target_link_libraries(global-symbol-builder + PRIVATE + clangAST + clangIndex + clangDaemon + clangBasic + clangFrontend + clangTooling +) Index: clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp =================================================================== --- /dev/null +++ clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp @@ -0,0 +1,127 @@ +//===--- GlobalSymbolBuilderMain.cpp -----------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// GlobalSymbolBuilder is a tool to generate YAML-format symbols across the +// whole project. This tools is for **experimental** only. Don't use it in +// production code. +// +//===---------------------------------------------------------------------===// + +#include "index/Index.h" +#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/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ThreadPool.h" + +using namespace llvm; +using namespace clang::tooling; +using clang::clangd::SymbolSlab; + +namespace clang { +namespace clangd { + +class SymbolIndexActionFactory : public tooling::FrontendActionFactory { +public: + SymbolIndexActionFactory() = default; + + 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(); + } + + std::shared_ptr Collector; +}; + +} // namespace clangd +} // namespace clang + +static cl::OptionCategory GlobalSymbolCategory("global-symbol-builder options"); + +static cl::opt ResultPath("result-path", cl::desc(R"( +File path for storing global symbols.)"), + cl::init("./clangd-global-symbols.yaml"), + cl::cat(GlobalSymbolCategory)); + +bool WriteFile(llvm::StringRef OutputFile, const SymbolSlab& Symbols) { + std::error_code EC; + llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_None); + if (EC) { + llvm::errs() << "Can't open '" << OutputFile << "': " << EC.message() + << '\n'; + return false; + } + OS << clang::clangd::SymbolToYAML(Symbols); + return true; +} + +int main(int argc, const char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + + const char* Overview = + "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, GlobalSymbolCategory, + /*Overview=*/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()) { + ClangTool Tool(OptionsParser.getCompilations(), + OptionsParser.getSourcePathList()); + clang::clangd::SymbolIndexActionFactory IndexAction; + Tool.run(&IndexAction); + llvm::outs() << SymbolToYAML(IndexAction.Collector->takeSymbols()); + return 0; + } + + // Found compilation database, we iterate all TUs from database to get all + // symbols, and then merge them into a single SymbolSlab. + SymbolSlab GlobalSymbols; + std::mutex SymbolMutex; + auto AddSymbols = [&](const SymbolSlab& NewSymbols) { + // Synchronize set accesses. + std::unique_lock LockGuard(SymbolMutex); + for (auto It : 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(It.second); + } + }; + + { + 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); + } + } + + WriteFile(ResultPath, GlobalSymbols); + return 0; +}