97d8d1283b6351615877a9f8d52f84329c01af74
[lldb.git] / clang-tools-extra / clangd / indexer / IndexerMain.cpp
1 //===--- IndexerMain.cpp -----------------------------------------*- C++-*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // clangd-indexer is a tool to gather index data (symbols, xrefs) from source.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "index/IndexAction.h"
14 #include "index/Merge.h"
15 #include "index/Ref.h"
16 #include "index/Serialization.h"
17 #include "index/Symbol.h"
18 #include "index/SymbolCollector.h"
19 #include "clang/Tooling/ArgumentsAdjusters.h"
20 #include "clang/Tooling/CommonOptionsParser.h"
21 #include "clang/Tooling/Execution.h"
22 #include "clang/Tooling/Tooling.h"
23 #include "llvm/Support/CommandLine.h"
24 #include "llvm/Support/Signals.h"
25
26 namespace clang {
27 namespace clangd {
28 namespace {
29
30 static llvm::cl::opt<IndexFileFormat>
31     Format("format", llvm::cl::desc("Format of the index to be written"),
32            llvm::cl::values(clEnumValN(IndexFileFormat::YAML, "yaml",
33                                        "human-readable YAML format"),
34                             clEnumValN(IndexFileFormat::RIFF, "binary",
35                                        "binary RIFF format")),
36            llvm::cl::init(IndexFileFormat::RIFF));
37
38 class IndexActionFactory : public tooling::FrontendActionFactory {
39 public:
40   IndexActionFactory(IndexFileIn &Result) : Result(Result) {}
41
42   clang::FrontendAction *create() override {
43     SymbolCollector::Options Opts;
44     Opts.CountReferences = true;
45     return createStaticIndexingAction(
46                Opts,
47                [&](SymbolSlab S) {
48                  // Merge as we go.
49                  std::lock_guard<std::mutex> Lock(SymbolsMu);
50                  for (const auto &Sym : S) {
51                    if (const auto *Existing = Symbols.find(Sym.ID))
52                      Symbols.insert(mergeSymbol(*Existing, Sym));
53                    else
54                      Symbols.insert(Sym);
55                  }
56                },
57                [&](RefSlab S) {
58                  std::lock_guard<std::mutex> Lock(SymbolsMu);
59                  for (const auto &Sym : S) {
60                    // Deduplication happens during insertion.
61                    for (const auto &Ref : Sym.second)
62                      Refs.insert(Sym.first, Ref);
63                  }
64                },
65                [&](RelationSlab S) {
66                  std::lock_guard<std::mutex> Lock(SymbolsMu);
67                  for (const auto &R : S) {
68                    Relations.insert(R);
69                  }
70                },
71                /*IncludeGraphCallback=*/nullptr)
72         .release();
73   }
74
75   // Awkward: we write the result in the destructor, because the executor
76   // takes ownership so it's the easiest way to get our data back out.
77   ~IndexActionFactory() {
78     Result.Symbols = std::move(Symbols).build();
79     Result.Refs = std::move(Refs).build();
80     Result.Relations = std::move(Relations).build();
81   }
82
83 private:
84   IndexFileIn &Result;
85   std::mutex SymbolsMu;
86   SymbolSlab::Builder Symbols;
87   RefSlab::Builder Refs;
88   RelationSlab::Builder Relations;
89 };
90
91 } // namespace
92 } // namespace clangd
93 } // namespace clang
94
95 int main(int argc, const char **argv) {
96   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
97
98   const char *Overview = R"(
99   Creates an index of symbol information etc in a whole project.
100
101   Example usage for a project using CMake compile commands:
102
103   $ clangd-indexer --executor=all-TUs compile_commands.json > clangd.dex
104
105   Example usage for file sequence index without flags:
106
107   $ clangd-indexer File1.cpp File2.cpp ... FileN.cpp > clangd.dex
108
109   Note: only symbols from header files will be indexed.
110   )";
111
112   auto Executor = clang::tooling::createExecutorFromCommandLineArgs(
113       argc, argv, llvm::cl::GeneralCategory, Overview);
114
115   if (!Executor) {
116     llvm::errs() << llvm::toString(Executor.takeError()) << "\n";
117     return 1;
118   }
119
120   // Collect symbols found in each translation unit, merging as we go.
121   clang::clangd::IndexFileIn Data;
122   auto Err = Executor->get()->execute(
123       std::make_unique<clang::clangd::IndexActionFactory>(Data),
124       clang::tooling::getStripPluginsAdjuster());
125   if (Err) {
126     llvm::errs() << llvm::toString(std::move(Err)) << "\n";
127   }
128
129   // Emit collected data.
130   clang::clangd::IndexFileOut Out(Data);
131   Out.Format = clang::clangd::Format;
132   llvm::outs() << Out;
133   return 0;
134 }