1 //===--- IndexerMain.cpp -----------------------------------------*- C++-*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // clangd-indexer is a tool to gather index data (symbols, xrefs) from source.
11 //===----------------------------------------------------------------------===//
13 #include "CompileCommands.h"
15 #include "index/IndexAction.h"
16 #include "index/Merge.h"
17 #include "index/Ref.h"
18 #include "index/Serialization.h"
19 #include "index/Symbol.h"
20 #include "index/SymbolCollector.h"
21 #include "support/Logger.h"
22 #include "clang/Tooling/ArgumentsAdjusters.h"
23 #include "clang/Tooling/Execution.h"
24 #include "clang/Tooling/Tooling.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/Signals.h"
33 static llvm::cl::opt
<IndexFileFormat
>
34 Format("format", llvm::cl::desc("Format of the index to be written"),
35 llvm::cl::values(clEnumValN(IndexFileFormat::YAML
, "yaml",
36 "human-readable YAML format"),
37 clEnumValN(IndexFileFormat::RIFF
, "binary",
38 "binary RIFF format")),
39 llvm::cl::init(IndexFileFormat::RIFF
));
41 class IndexActionFactory
: public tooling::FrontendActionFactory
{
43 IndexActionFactory(IndexFileIn
&Result
) : Result(Result
) {}
45 std::unique_ptr
<FrontendAction
> create() override
{
46 SymbolCollector::Options Opts
;
47 Opts
.CountReferences
= true;
48 Opts
.FileFilter
= [&](const SourceManager
&SM
, FileID FID
) {
49 const auto F
= SM
.getFileEntryRefForID(FID
);
51 return false; // Skip invalid files.
52 auto AbsPath
= getCanonicalPath(*F
, SM
.getFileManager());
54 return false; // Skip files without absolute path.
55 std::lock_guard
<std::mutex
> Lock(FilesMu
);
56 return Files
.insert(*AbsPath
).second
; // Skip already processed files.
58 return createStaticIndexingAction(
62 std::lock_guard
<std::mutex
> Lock(SymbolsMu
);
63 for (const auto &Sym
: S
) {
64 if (const auto *Existing
= Symbols
.find(Sym
.ID
))
65 Symbols
.insert(mergeSymbol(*Existing
, Sym
));
71 std::lock_guard
<std::mutex
> Lock(RefsMu
);
72 for (const auto &Sym
: S
) {
73 // Deduplication happens during insertion.
74 for (const auto &Ref
: Sym
.second
)
75 Refs
.insert(Sym
.first
, Ref
);
79 std::lock_guard
<std::mutex
> Lock(RelsMu
);
80 for (const auto &R
: S
) {
84 /*IncludeGraphCallback=*/nullptr);
87 bool runInvocation(std::shared_ptr
<CompilerInvocation
> Invocation
,
89 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
,
90 DiagnosticConsumer
*DiagConsumer
) override
{
91 disableUnsupportedOptions(*Invocation
);
92 return tooling::FrontendActionFactory::runInvocation(
93 std::move(Invocation
), Files
, std::move(PCHContainerOps
), DiagConsumer
);
96 // Awkward: we write the result in the destructor, because the executor
97 // takes ownership so it's the easiest way to get our data back out.
98 ~IndexActionFactory() {
99 Result
.Symbols
= std::move(Symbols
).build();
100 Result
.Refs
= std::move(Refs
).build();
101 Result
.Relations
= std::move(Relations
).build();
107 llvm::StringSet
<> Files
;
108 std::mutex SymbolsMu
;
109 SymbolSlab::Builder Symbols
;
111 RefSlab::Builder Refs
;
113 RelationSlab::Builder Relations
;
117 } // namespace clangd
120 int main(int argc
, const char **argv
) {
121 llvm::sys::PrintStackTraceOnErrorSignal(argv
[0]);
123 const char *Overview
= R
"(
124 Creates an index of symbol information etc in a whole project.
126 Example usage for a project using CMake compile commands:
128 $ clangd-indexer --executor=all-TUs compile_commands.json > clangd.dex
130 Example usage for file sequence index without flags:
132 $ clangd-indexer File1.cpp File2.cpp ... FileN.cpp > clangd.dex
134 Note: only symbols from header files will be indexed.
137 auto Executor
= clang::tooling::createExecutorFromCommandLineArgs(
138 argc
, argv
, llvm::cl::getGeneralCategory(), Overview
);
141 llvm::errs() << llvm::toString(Executor
.takeError()) << "\n";
145 // Collect symbols found in each translation unit, merging as we go.
146 clang::clangd::IndexFileIn Data
;
147 auto Err
= Executor
->get()->execute(
148 std::make_unique
<clang::clangd::IndexActionFactory
>(Data
),
149 clang::tooling::ArgumentsAdjuster(
150 [Mangler
= std::make_shared
<clang::clangd::CommandMangler
>(
151 clang::clangd::CommandMangler::detect())](
152 const std::vector
<std::string
> &Args
, llvm::StringRef File
) {
153 clang::tooling::CompileCommand Cmd
;
154 Cmd
.CommandLine
= Args
;
155 Mangler
->operator()(Cmd
, File
);
156 return Cmd
.CommandLine
;
159 clang::clangd::elog("{0}", std::move(Err
));
162 // Emit collected data.
163 clang::clangd::IndexFileOut
Out(Data
);
164 Out
.Format
= clang::clangd::Format
;