blob: 15a7158fb305a0937f00a26f837bc4bb710d12a3 [file] [log] [blame]
Benjamin Kramer6b236262016-04-20 12:43:43 +00001//===-- ClangIncludeFixer.cpp - Standalone include fixer ------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Benjamin Kramera3d82332016-05-13 09:27:54 +000010#include "InMemorySymbolIndex.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000011#include "IncludeFixer.h"
Haojian Wu11e9bd22016-05-31 09:31:51 +000012#include "IncludeFixerContext.h"
Benjamin Kramera3d82332016-05-13 09:27:54 +000013#include "SymbolIndexManager.h"
14#include "YamlSymbolIndex.h"
Haojian Wu11e9bd22016-05-31 09:31:51 +000015#include "clang/Format/Format.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000016#include "clang/Frontend/TextDiagnosticPrinter.h"
17#include "clang/Rewrite/Core/Rewriter.h"
18#include "clang/Tooling/CommonOptionsParser.h"
Haojian Wu627ca962016-07-08 09:10:29 +000019#include "clang/Tooling/Core/Replacement.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000020#include "clang/Tooling/Tooling.h"
21#include "llvm/Support/CommandLine.h"
Benjamin Kramer8ff8fdf2016-07-18 19:21:22 +000022#include "llvm/Support/Path.h"
Haojian Wu17a54e32016-06-01 11:43:10 +000023#include "llvm/Support/YAMLTraits.h"
Haojian Wud8c12ba2016-04-29 09:23:38 +000024
Benjamin Kramer6b236262016-04-20 12:43:43 +000025using namespace clang;
Benjamin Kramerf412e902016-04-27 14:24:32 +000026using namespace llvm;
Haojian Wu17a54e32016-06-01 11:43:10 +000027using clang::include_fixer::IncludeFixerContext;
28
29LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(IncludeFixerContext)
30LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
Haojian Wu68c34a02016-07-13 16:43:54 +000031LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::HeaderInfo)
Haojian Wu62aee522016-07-21 13:47:09 +000032LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::QuerySymbolInfo)
Haojian Wu17a54e32016-06-01 11:43:10 +000033
34namespace llvm {
35namespace yaml {
Haojian Wu68c34a02016-07-13 16:43:54 +000036
37template <> struct MappingTraits<tooling::Range> {
38 struct NormalizedRange {
39 NormalizedRange(const IO &) : Offset(0), Length(0) {}
40
41 NormalizedRange(const IO &, const tooling::Range &R)
42 : Offset(R.getOffset()), Length(R.getLength()) {}
43
44 tooling::Range denormalize(const IO &) {
45 return tooling::Range(Offset, Length);
46 }
47
48 unsigned Offset;
49 unsigned Length;
50 };
51 static void mapping(IO &IO, tooling::Range &Info) {
52 MappingNormalization<NormalizedRange, tooling::Range> Keys(IO, Info);
53 IO.mapRequired("Offset", Keys->Offset);
54 IO.mapRequired("Length", Keys->Length);
55 }
56};
57
58template <> struct MappingTraits<IncludeFixerContext::HeaderInfo> {
59 static void mapping(IO &io, IncludeFixerContext::HeaderInfo &Info) {
60 io.mapRequired("Header", Info.Header);
61 io.mapRequired("QualifiedName", Info.QualifiedName);
62 }
63};
64
Haojian Wu9e4bd0c2016-07-19 14:49:04 +000065template <> struct MappingTraits<IncludeFixerContext::QuerySymbolInfo> {
66 static void mapping(IO &io, IncludeFixerContext::QuerySymbolInfo &Info) {
67 io.mapRequired("RawIdentifier", Info.RawIdentifier);
68 io.mapRequired("Range", Info.Range);
69 }
70};
71
Haojian Wu17a54e32016-06-01 11:43:10 +000072template <> struct MappingTraits<IncludeFixerContext> {
Haojian Wu68c34a02016-07-13 16:43:54 +000073 static void mapping(IO &IO, IncludeFixerContext &Context) {
Haojian Wu62aee522016-07-21 13:47:09 +000074 IO.mapRequired("QuerySymbolInfos", Context.QuerySymbolInfos);
Haojian Wu68c34a02016-07-13 16:43:54 +000075 IO.mapRequired("HeaderInfos", Context.HeaderInfos);
Haojian Wuc99f7282016-08-09 08:26:19 +000076 IO.mapRequired("FilePath", Context.FilePath);
Haojian Wu17a54e32016-06-01 11:43:10 +000077 }
78};
79} // namespace yaml
80} // namespace llvm
Benjamin Kramer6b236262016-04-20 12:43:43 +000081
Benjamin Kramerf412e902016-04-27 14:24:32 +000082namespace {
83cl::OptionCategory IncludeFixerCategory("Tool options");
84
85enum DatabaseFormatTy {
Simon Pilgrimb9f25582016-04-27 20:43:32 +000086 fixed, ///< Hard-coded mapping.
Haojian Wud8c12ba2016-04-29 09:23:38 +000087 yaml, ///< Yaml database created by find-all-symbols.
Benjamin Kramerf412e902016-04-27 14:24:32 +000088};
89
90cl::opt<DatabaseFormatTy> DatabaseFormat(
91 "db", cl::desc("Specify input format"),
Haojian Wud8c12ba2016-04-29 09:23:38 +000092 cl::values(clEnumVal(fixed, "Hard-coded mapping"),
Mehdi Amini732afdd2016-10-08 19:41:06 +000093 clEnumVal(yaml, "Yaml database created by find-all-symbols")),
Benjamin Kramer8fd85a52016-05-10 11:35:47 +000094 cl::init(yaml), cl::cat(IncludeFixerCategory));
Benjamin Kramerf412e902016-04-27 14:24:32 +000095
96cl::opt<std::string> Input("input",
97 cl::desc("String to initialize the database"),
98 cl::cat(IncludeFixerCategory));
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000099
Haojian Wucd637012016-09-07 16:34:35 +0000100cl::opt<std::string>
101 QuerySymbol("query-symbol",
102 cl::desc("Query a given symbol (e.g. \"a::b::foo\") in\n"
103 "database directly without parsing the file."),
104 cl::cat(IncludeFixerCategory));
105
Benjamin Kramer3a45fab2016-04-28 11:21:29 +0000106cl::opt<bool>
107 MinimizeIncludePaths("minimize-paths",
108 cl::desc("Whether to minimize added include paths"),
109 cl::init(true), cl::cat(IncludeFixerCategory));
Benjamin Kramer6b236262016-04-20 12:43:43 +0000110
Benjamin Kramer54718292016-05-10 08:36:56 +0000111cl::opt<bool> Quiet("q", cl::desc("Reduce terminal output"), cl::init(false),
112 cl::cat(IncludeFixerCategory));
113
Eric Liuc7f3b102016-05-18 14:10:16 +0000114cl::opt<bool>
115 STDINMode("stdin",
116 cl::desc("Override source file's content (in the overlaying\n"
117 "virtual file system) with input from <stdin> and run\n"
118 "the tool on the new content with the compilation\n"
119 "options of the source file. This mode is currently\n"
120 "used for editor integration."),
121 cl::init(false), cl::cat(IncludeFixerCategory));
122
Haojian Wu11e9bd22016-05-31 09:31:51 +0000123cl::opt<bool> OutputHeaders(
124 "output-headers",
Haojian Wu17a54e32016-06-01 11:43:10 +0000125 cl::desc("Print the symbol being queried and all its relevant headers in\n"
126 "JSON format to stdout:\n"
127 " {\n"
Haojian Wuab372642016-08-17 11:31:19 +0000128 " \"FilePath\": \"/path/to/foo.cc\",\n"
Haojian Wu62aee522016-07-21 13:47:09 +0000129 " \"QuerySymbolInfos\": [\n"
130 " {\"RawIdentifier\": \"foo\",\n"
131 " \"Range\": {\"Offset\": 0, \"Length\": 3}}\n"
132 " ],\n"
Haojian Wu68c34a02016-07-13 16:43:54 +0000133 " \"HeaderInfos\": [ {\"Header\": \"\\\"foo_a.h\\\"\",\n"
134 " \"QualifiedName\": \"a::foo\"} ]\n"
Haojian Wu17a54e32016-06-01 11:43:10 +0000135 " }"),
Haojian Wu11e9bd22016-05-31 09:31:51 +0000136 cl::init(false), cl::cat(IncludeFixerCategory));
137
138cl::opt<std::string> InsertHeader(
139 "insert-header",
140 cl::desc("Insert a specific header. This should run with STDIN mode.\n"
141 "The result is written to stdout. It is currently used for\n"
Haojian Wu17a54e32016-06-01 11:43:10 +0000142 "editor integration. Support YAML/JSON format:\n"
Haojian Wu68c34a02016-07-13 16:43:54 +0000143 " -insert-header=\"{\n"
Haojian Wuab372642016-08-17 11:31:19 +0000144 " FilePath: \"/path/to/foo.cc\",\n"
Haojian Wu62aee522016-07-21 13:47:09 +0000145 " QuerySymbolInfos: [\n"
146 " {RawIdentifier: foo,\n"
147 " Range: {Offset: 0, Length: 3}}\n"
148 " ],\n"
Haojian Wu68c34a02016-07-13 16:43:54 +0000149 " HeaderInfos: [ {Headers: \"\\\"foo_a.h\\\"\",\n"
150 " QualifiedName: \"a::foo\"} ]}\""),
Haojian Wu11e9bd22016-05-31 09:31:51 +0000151 cl::init(""), cl::cat(IncludeFixerCategory));
152
Eric Liu702cfd12016-05-19 08:21:09 +0000153cl::opt<std::string>
154 Style("style",
Haojian Wuab372642016-08-17 11:31:19 +0000155 cl::desc("Fallback style for reformatting after inserting new\n"
Eric Liu702cfd12016-05-19 08:21:09 +0000156 "headers if there is no clang-format config file found."),
157 cl::init("llvm"), cl::cat(IncludeFixerCategory));
158
Haojian Wueb6ce062016-05-31 13:23:00 +0000159std::unique_ptr<include_fixer::SymbolIndexManager>
160createSymbolIndexManager(StringRef FilePath) {
161 auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
162 switch (DatabaseFormat) {
163 case fixed: {
164 // Parse input and fill the database with it.
165 // <symbol>=<header><, header...>
166 // Multiple symbols can be given, separated by semicolons.
167 std::map<std::string, std::vector<std::string>> SymbolsMap;
168 SmallVector<StringRef, 4> SemicolonSplits;
169 StringRef(Input).split(SemicolonSplits, ";");
170 std::vector<find_all_symbols::SymbolInfo> Symbols;
171 for (StringRef Pair : SemicolonSplits) {
172 auto Split = Pair.split('=');
173 std::vector<std::string> Headers;
174 SmallVector<StringRef, 4> CommaSplits;
175 Split.second.split(CommaSplits, ",");
Benjamin Kramer658d2802016-05-31 14:33:28 +0000176 for (size_t I = 0, E = CommaSplits.size(); I != E; ++I)
Haojian Wueb6ce062016-05-31 13:23:00 +0000177 Symbols.push_back(find_all_symbols::SymbolInfo(
178 Split.first.trim(),
Benjamin Kramer658d2802016-05-31 14:33:28 +0000179 find_all_symbols::SymbolInfo::SymbolKind::Unknown,
180 CommaSplits[I].trim(), 1, {}, /*NumOccurrences=*/E - I));
Haojian Wueb6ce062016-05-31 13:23:00 +0000181 }
Benjamin Kramerbdb21712017-01-09 15:18:28 +0000182 SymbolIndexMgr->addSymbolIndex([=]() {
183 return llvm::make_unique<include_fixer::InMemorySymbolIndex>(Symbols);
184 });
Haojian Wueb6ce062016-05-31 13:23:00 +0000185 break;
186 }
187 case yaml: {
Benjamin Kramerbdb21712017-01-09 15:18:28 +0000188 auto CreateYamlIdx = [=]() -> std::unique_ptr<include_fixer::SymbolIndex> {
189 llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> DB(
190 nullptr);
191 if (!Input.empty()) {
192 DB = include_fixer::YamlSymbolIndex::createFromFile(Input);
193 } else {
194 // If we don't have any input file, look in the directory of the
195 // first
196 // file and its parents.
197 SmallString<128> AbsolutePath(tooling::getAbsolutePath(FilePath));
198 StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
199 DB = include_fixer::YamlSymbolIndex::createFromDirectory(
200 Directory, "find_all_symbols_db.yaml");
201 }
Haojian Wueb6ce062016-05-31 13:23:00 +0000202
Benjamin Kramerbdb21712017-01-09 15:18:28 +0000203 if (!DB) {
204 llvm::errs() << "Couldn't find YAML db: " << DB.getError().message()
205 << '\n';
206 return nullptr;
207 }
208 return std::move(*DB);
209 };
Haojian Wueb6ce062016-05-31 13:23:00 +0000210
Benjamin Kramerbdb21712017-01-09 15:18:28 +0000211 SymbolIndexMgr->addSymbolIndex(std::move(CreateYamlIdx));
Haojian Wueb6ce062016-05-31 13:23:00 +0000212 break;
213 }
214 }
215 return SymbolIndexMgr;
216}
217
Haojian Wu17a54e32016-06-01 11:43:10 +0000218void writeToJson(llvm::raw_ostream &OS, const IncludeFixerContext& Context) {
219 OS << "{\n"
Haojian Wuc99f7282016-08-09 08:26:19 +0000220 << " \"FilePath\": \""
221 << llvm::yaml::escape(Context.getFilePath()) << "\",\n"
222 << " \"QuerySymbolInfos\": [\n";
Haojian Wu62aee522016-07-21 13:47:09 +0000223 for (const auto &Info : Context.getQuerySymbolInfos()) {
224 OS << " {\"RawIdentifier\": \"" << Info.RawIdentifier << "\",\n";
225 OS << " \"Range\":{";
226 OS << "\"Offset\":" << Info.Range.getOffset() << ",";
227 OS << "\"Length\":" << Info.Range.getLength() << "}}";
228 if (&Info != &Context.getQuerySymbolInfos().back())
229 OS << ",\n";
230 }
231 OS << "\n ],\n";
Haojian Wu68c34a02016-07-13 16:43:54 +0000232 OS << " \"HeaderInfos\": [\n";
233 const auto &HeaderInfos = Context.getHeaderInfos();
234 for (const auto &Info : HeaderInfos) {
235 OS << " {\"Header\": \"" << llvm::yaml::escape(Info.Header) << "\",\n"
236 << " \"QualifiedName\": \"" << Info.QualifiedName << "\"}";
237 if (&Info != &HeaderInfos.back())
238 OS << ",\n";
Haojian Wu17a54e32016-06-01 11:43:10 +0000239 }
Haojian Wu68c34a02016-07-13 16:43:54 +0000240 OS << "\n";
241 OS << " ]\n";
242 OS << "}\n";
Haojian Wu17a54e32016-06-01 11:43:10 +0000243}
244
Haojian Wua315dcb2016-05-03 08:38:35 +0000245int includeFixerMain(int argc, const char **argv) {
Benjamin Kramerf412e902016-04-27 14:24:32 +0000246 tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory);
247 tooling::ClangTool tool(options.getCompilations(),
248 options.getSourcePathList());
249
Haojian Wucd637012016-09-07 16:34:35 +0000250 llvm::StringRef SourceFilePath = options.getSourcePathList().front();
Eric Liuc7f3b102016-05-18 14:10:16 +0000251 // In STDINMode, we override the file content with the <stdin> input.
252 // Since `tool.mapVirtualFile` takes `StringRef`, we define `Code` outside of
253 // the if-block so that `Code` is not released after the if-block.
254 std::unique_ptr<llvm::MemoryBuffer> Code;
255 if (STDINMode) {
256 assert(options.getSourcePathList().size() == 1 &&
257 "Expect exactly one file path in STDINMode.");
258 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CodeOrErr =
259 MemoryBuffer::getSTDIN();
260 if (std::error_code EC = CodeOrErr.getError()) {
261 errs() << EC.message() << "\n";
262 return 1;
263 }
264 Code = std::move(CodeOrErr.get());
265 if (Code->getBufferSize() == 0)
266 return 0; // Skip empty files.
267
Haojian Wucd637012016-09-07 16:34:35 +0000268 tool.mapVirtualFile(SourceFilePath, Code->getBuffer());
Eric Liuc7f3b102016-05-18 14:10:16 +0000269 }
270
Haojian Wu11e9bd22016-05-31 09:31:51 +0000271 if (!InsertHeader.empty()) {
272 if (!STDINMode) {
273 errs() << "Should be running in STDIN mode\n";
274 return 1;
275 }
276
Haojian Wu17a54e32016-06-01 11:43:10 +0000277 llvm::yaml::Input yin(InsertHeader);
278 IncludeFixerContext Context;
279 yin >> Context;
280
Haojian Wu68c34a02016-07-13 16:43:54 +0000281 const auto &HeaderInfos = Context.getHeaderInfos();
282 assert(!HeaderInfos.empty());
283 // We only accept one unique header.
284 // Check all elements in HeaderInfos have the same header.
285 bool IsUniqueHeader = std::equal(
286 HeaderInfos.begin()+1, HeaderInfos.end(), HeaderInfos.begin(),
287 [](const IncludeFixerContext::HeaderInfo &LHS,
288 const IncludeFixerContext::HeaderInfo &RHS) {
289 return LHS.Header == RHS.Header;
290 });
291 if (!IsUniqueHeader) {
292 errs() << "Expect exactly one unique header.\n";
Haojian Wu17a54e32016-06-01 11:43:10 +0000293 return 1;
294 }
295
Haojian Wu62aee522016-07-21 13:47:09 +0000296 // If a header has multiple symbols, we won't add the missing namespace
Haojian Wu68c34a02016-07-13 16:43:54 +0000297 // qualifiers because we don't know which one is exactly used.
298 //
299 // Check whether all elements in HeaderInfos have the same qualified name.
300 bool IsUniqueQualifiedName = std::equal(
301 HeaderInfos.begin() + 1, HeaderInfos.end(), HeaderInfos.begin(),
302 [](const IncludeFixerContext::HeaderInfo &LHS,
303 const IncludeFixerContext::HeaderInfo &RHS) {
304 return LHS.QualifiedName == RHS.QualifiedName;
305 });
Antonio Maiorano0d7d9c22017-01-17 00:13:32 +0000306 auto InsertStyle = format::getStyle("file", Context.getFilePath(), Style);
307 if (!InsertStyle) {
308 llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
309 return 1;
310 }
Haojian Wu62aee522016-07-21 13:47:09 +0000311 auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
Antonio Maiorano0d7d9c22017-01-17 00:13:32 +0000312 Code->getBuffer(), Context, *InsertStyle,
Haojian Wu62aee522016-07-21 13:47:09 +0000313 /*AddQualifiers=*/IsUniqueQualifiedName);
314 if (!Replacements) {
315 errs() << "Failed to create replacements: "
316 << llvm::toString(Replacements.takeError()) << "\n";
317 return 1;
318 }
319
Eric Liua452db42016-07-11 13:53:21 +0000320 auto ChangedCode =
321 tooling::applyAllReplacements(Code->getBuffer(), *Replacements);
322 if (!ChangedCode) {
323 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
324 return 1;
325 }
326 llvm::outs() << *ChangedCode;
Haojian Wu11e9bd22016-05-31 09:31:51 +0000327 return 0;
328 }
329
Eric Liu692aca62016-05-04 08:22:35 +0000330 // Set up data source.
Haojian Wueb6ce062016-05-31 13:23:00 +0000331 std::unique_ptr<include_fixer::SymbolIndexManager> SymbolIndexMgr =
Haojian Wucd637012016-09-07 16:34:35 +0000332 createSymbolIndexManager(SourceFilePath);
Haojian Wueb6ce062016-05-31 13:23:00 +0000333 if (!SymbolIndexMgr)
334 return 1;
Benjamin Kramer6b236262016-04-20 12:43:43 +0000335
Haojian Wucd637012016-09-07 16:34:35 +0000336 // Query symbol mode.
337 if (!QuerySymbol.empty()) {
Manuel Klimeka47515e2017-01-11 10:32:47 +0000338 auto MatchedSymbols = SymbolIndexMgr->search(
339 QuerySymbol, /*IsNestedSearch=*/true, SourceFilePath);
Haojian Wucd637012016-09-07 16:34:35 +0000340 for (auto &Symbol : MatchedSymbols) {
341 std::string HeaderPath = Symbol.getFilePath().str();
342 Symbol.SetFilePath(((HeaderPath[0] == '"' || HeaderPath[0] == '<')
343 ? HeaderPath
344 : "\"" + HeaderPath + "\""));
345 }
346
347 // We leave an empty symbol range as we don't know the range of the symbol
348 // being queried in this mode. include-fixer won't add namespace qualifiers
349 // if the symbol range is empty, which also fits this case.
350 IncludeFixerContext::QuerySymbolInfo Symbol;
351 Symbol.RawIdentifier = QuerySymbol;
352 auto Context =
353 IncludeFixerContext(SourceFilePath, {Symbol}, MatchedSymbols);
354 writeToJson(llvm::outs(), Context);
355 return 0;
356 }
357
Benjamin Kramer6b236262016-04-20 12:43:43 +0000358 // Now run our tool.
Haojian Wuc99f7282016-08-09 08:26:19 +0000359 std::vector<include_fixer::IncludeFixerContext> Contexts;
360 include_fixer::IncludeFixerActionFactory Factory(*SymbolIndexMgr, Contexts,
Haojian Wu11e9bd22016-05-31 09:31:51 +0000361 Style, MinimizeIncludePaths);
Benjamin Kramer6b236262016-04-20 12:43:43 +0000362
Benjamin Kramer6b5160a2016-05-18 13:32:38 +0000363 if (tool.run(&Factory) != 0) {
Benjamin Kramer2df9a3f2016-10-28 13:00:49 +0000364 // We suppress all Clang diagnostics (because they would be wrong,
365 // include-fixer does custom recovery) but still want to give some feedback
366 // in case there was a compiler error we couldn't recover from. The most
367 // common case for this is a #include in the file that couldn't be found.
368 llvm::errs() << "Fatal compiler error occurred while parsing file!"
369 " (incorrect include paths?)\n";
Benjamin Kramer6b5160a2016-05-18 13:32:38 +0000370 return 1;
371 }
Benjamin Kramer6b236262016-04-20 12:43:43 +0000372
Haojian Wuc99f7282016-08-09 08:26:19 +0000373 assert(!Contexts.empty());
374
Haojian Wu11e9bd22016-05-31 09:31:51 +0000375 if (OutputHeaders) {
Haojian Wuc99f7282016-08-09 08:26:19 +0000376 // FIXME: Print contexts of all processing files instead of the first one.
377 writeToJson(llvm::outs(), Contexts.front());
Haojian Wu11e9bd22016-05-31 09:31:51 +0000378 return 0;
379 }
380
Haojian Wuc99f7282016-08-09 08:26:19 +0000381 std::vector<tooling::Replacements> FixerReplacements;
382 for (const auto &Context : Contexts) {
383 StringRef FilePath = Context.getFilePath();
Antonio Maiorano0d7d9c22017-01-17 00:13:32 +0000384 auto InsertStyle = format::getStyle("file", FilePath, Style);
385 if (!InsertStyle) {
386 llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
387 return 1;
388 }
Haojian Wuc99f7282016-08-09 08:26:19 +0000389 auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
390 if (!Buffer) {
391 errs() << "Couldn't open file: " + FilePath.str() + ": "
392 << Buffer.getError().message() + "\n";
393 return 1;
394 }
Haojian Wu11e9bd22016-05-31 09:31:51 +0000395
Haojian Wuc99f7282016-08-09 08:26:19 +0000396 auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
Antonio Maiorano0d7d9c22017-01-17 00:13:32 +0000397 Buffer.get()->getBuffer(), Context, *InsertStyle);
Haojian Wuc99f7282016-08-09 08:26:19 +0000398 if (!Replacements) {
399 errs() << "Failed to create replacement: "
400 << llvm::toString(Replacements.takeError()) << "\n";
401 return 1;
402 }
403 FixerReplacements.push_back(*Replacements);
Haojian Wu11e9bd22016-05-31 09:31:51 +0000404 }
405
Haojian Wuc99f7282016-08-09 08:26:19 +0000406 if (!Quiet) {
407 for (const auto &Context : Contexts) {
408 if (!Context.getHeaderInfos().empty()) {
409 llvm::errs() << "Added #include "
410 << Context.getHeaderInfos().front().Header << " for "
411 << Context.getFilePath() << "\n";
412 }
413 }
Eric Liua452db42016-07-11 13:53:21 +0000414 }
Haojian Wu11e9bd22016-05-31 09:31:51 +0000415
Eric Liuc7f3b102016-05-18 14:10:16 +0000416 if (STDINMode) {
Haojian Wuc99f7282016-08-09 08:26:19 +0000417 assert(FixerReplacements.size() == 1);
418 auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(),
419 FixerReplacements.front());
Eric Liua452db42016-07-11 13:53:21 +0000420 if (!ChangedCode) {
421 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
422 return 1;
423 }
424 llvm::outs() << *ChangedCode;
Eric Liuc7f3b102016-05-18 14:10:16 +0000425 return 0;
426 }
427
Haojian Wuc99f7282016-08-09 08:26:19 +0000428 // Set up a new source manager for applying the resulting replacements.
429 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
430 DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
431 TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
432 SourceManager SM(Diagnostics, tool.getFiles());
433 Diagnostics.setClient(&DiagnosticPrinter, false);
434
Benjamin Kramer6b236262016-04-20 12:43:43 +0000435 // Write replacements to disk.
Benjamin Kramerf412e902016-04-27 14:24:32 +0000436 Rewriter Rewrites(SM, LangOptions());
Benjamin Kramer089a39e2016-10-19 13:50:17 +0000437 for (const auto &Replacement : FixerReplacements) {
Haojian Wuc99f7282016-08-09 08:26:19 +0000438 if (!tooling::applyAllReplacements(Replacement, Rewrites)) {
439 llvm::errs() << "Failed to apply replacements.\n";
440 return 1;
441 }
442 }
Benjamin Kramer6b236262016-04-20 12:43:43 +0000443 return Rewrites.overwriteChangedFiles();
444}
Haojian Wua315dcb2016-05-03 08:38:35 +0000445
446} // namespace
447
448int main(int argc, const char **argv) {
449 return includeFixerMain(argc, argv);
450}