//===--- IndexerMain.cpp -----------------------------------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // clangd-indexer is a tool to gather index data (symbols, xrefs) from source. // //===----------------------------------------------------------------------===// #include "index/IndexAction.h" #include "index/Merge.h" #include "index/Ref.h" #include "index/Serialization.h" #include "index/Symbol.h" #include "index/SymbolCollector.h" #include "support/Logger.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Execution.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Signals.h" namespace clang { namespace clangd { namespace { static llvm::cl::opt Format("format", llvm::cl::desc("Format of the index to be written"), llvm::cl::values(clEnumValN(IndexFileFormat::YAML, "yaml", "human-readable YAML format"), clEnumValN(IndexFileFormat::RIFF, "binary", "binary RIFF format")), llvm::cl::init(IndexFileFormat::RIFF)); class IndexActionFactory : public tooling::FrontendActionFactory { public: IndexActionFactory(IndexFileIn &Result) : Result(Result) {} std::unique_ptr create() override { SymbolCollector::Options Opts; Opts.CountReferences = true; Opts.FileFilter = [&](const SourceManager &SM, FileID FID) { const auto *F = SM.getFileEntryForID(FID); if (!F) return false; // Skip invalid files. auto AbsPath = getCanonicalPath(F, SM); if (!AbsPath) return false; // Skip files without absolute path. std::lock_guard Lock(FilesMu); return Files.insert(*AbsPath).second; // Skip already processed files. }; return createStaticIndexingAction( Opts, [&](SymbolSlab S) { // Merge as we go. std::lock_guard Lock(SymbolsMu); for (const auto &Sym : S) { if (const auto *Existing = Symbols.find(Sym.ID)) Symbols.insert(mergeSymbol(*Existing, Sym)); else Symbols.insert(Sym); } }, [&](RefSlab S) { std::lock_guard Lock(RefsMu); for (const auto &Sym : S) { // Deduplication happens during insertion. for (const auto &Ref : Sym.second) Refs.insert(Sym.first, Ref); } }, [&](RelationSlab S) { std::lock_guard Lock(RelsMu); for (const auto &R : S) { Relations.insert(R); } }, /*IncludeGraphCallback=*/nullptr); } // Awkward: we write the result in the destructor, because the executor // takes ownership so it's the easiest way to get our data back out. ~IndexActionFactory() { Result.Symbols = std::move(Symbols).build(); Result.Refs = std::move(Refs).build(); Result.Relations = std::move(Relations).build(); } private: IndexFileIn &Result; std::mutex FilesMu; llvm::StringSet<> Files; std::mutex SymbolsMu; SymbolSlab::Builder Symbols; std::mutex RefsMu; RefSlab::Builder Refs; std::mutex RelsMu; RelationSlab::Builder Relations; }; } // namespace } // namespace clangd } // namespace clang int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); const char *Overview = R"( Creates an index of symbol information etc in a whole project. Example usage for a project using CMake compile commands: $ clangd-indexer --executor=all-TUs compile_commands.json > clangd.dex Example usage for file sequence index without flags: $ clangd-indexer File1.cpp File2.cpp ... FileN.cpp > clangd.dex Note: only symbols from header files will be indexed. )"; auto Executor = clang::tooling::createExecutorFromCommandLineArgs( argc, argv, llvm::cl::GeneralCategory, Overview); if (!Executor) { llvm::errs() << llvm::toString(Executor.takeError()) << "\n"; return 1; } // Collect symbols found in each translation unit, merging as we go. clang::clangd::IndexFileIn Data; auto Err = Executor->get()->execute( std::make_unique(Data), clang::tooling::getStripPluginsAdjuster()); if (Err) { clang::clangd::elog("{0}", std::move(Err)); } // Emit collected data. clang::clangd::IndexFileOut Out(Data); Out.Format = clang::clangd::Format; llvm::outs() << Out; return 0; }