blob: 969ac37794e8176d9bf0969e601416372862aeba [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 }
182 SymbolIndexMgr->addSymbolIndex(
183 llvm::make_unique<include_fixer::InMemorySymbolIndex>(Symbols));
184 break;
185 }
186 case yaml: {
187 llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> DB(nullptr);
188 if (!Input.empty()) {
189 DB = include_fixer::YamlSymbolIndex::createFromFile(Input);
190 } else {
191 // If we don't have any input file, look in the directory of the first
192 // file and its parents.
193 SmallString<128> AbsolutePath(tooling::getAbsolutePath(FilePath));
194 StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
195 DB = include_fixer::YamlSymbolIndex::createFromDirectory(
196 Directory, "find_all_symbols_db.yaml");
197 }
198
199 if (!DB) {
200 llvm::errs() << "Couldn't find YAML db: " << DB.getError().message()
201 << '\n';
202 return nullptr;
203 }
204
205 SymbolIndexMgr->addSymbolIndex(std::move(*DB));
206 break;
207 }
208 }
209 return SymbolIndexMgr;
210}
211
Haojian Wu17a54e32016-06-01 11:43:10 +0000212void writeToJson(llvm::raw_ostream &OS, const IncludeFixerContext& Context) {
213 OS << "{\n"
Haojian Wuc99f7282016-08-09 08:26:19 +0000214 << " \"FilePath\": \""
215 << llvm::yaml::escape(Context.getFilePath()) << "\",\n"
216 << " \"QuerySymbolInfos\": [\n";
Haojian Wu62aee522016-07-21 13:47:09 +0000217 for (const auto &Info : Context.getQuerySymbolInfos()) {
218 OS << " {\"RawIdentifier\": \"" << Info.RawIdentifier << "\",\n";
219 OS << " \"Range\":{";
220 OS << "\"Offset\":" << Info.Range.getOffset() << ",";
221 OS << "\"Length\":" << Info.Range.getLength() << "}}";
222 if (&Info != &Context.getQuerySymbolInfos().back())
223 OS << ",\n";
224 }
225 OS << "\n ],\n";
Haojian Wu68c34a02016-07-13 16:43:54 +0000226 OS << " \"HeaderInfos\": [\n";
227 const auto &HeaderInfos = Context.getHeaderInfos();
228 for (const auto &Info : HeaderInfos) {
229 OS << " {\"Header\": \"" << llvm::yaml::escape(Info.Header) << "\",\n"
230 << " \"QualifiedName\": \"" << Info.QualifiedName << "\"}";
231 if (&Info != &HeaderInfos.back())
232 OS << ",\n";
Haojian Wu17a54e32016-06-01 11:43:10 +0000233 }
Haojian Wu68c34a02016-07-13 16:43:54 +0000234 OS << "\n";
235 OS << " ]\n";
236 OS << "}\n";
Haojian Wu17a54e32016-06-01 11:43:10 +0000237}
238
Haojian Wua315dcb2016-05-03 08:38:35 +0000239int includeFixerMain(int argc, const char **argv) {
Benjamin Kramerf412e902016-04-27 14:24:32 +0000240 tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory);
241 tooling::ClangTool tool(options.getCompilations(),
242 options.getSourcePathList());
243
Haojian Wucd637012016-09-07 16:34:35 +0000244 llvm::StringRef SourceFilePath = options.getSourcePathList().front();
Eric Liuc7f3b102016-05-18 14:10:16 +0000245 // In STDINMode, we override the file content with the <stdin> input.
246 // Since `tool.mapVirtualFile` takes `StringRef`, we define `Code` outside of
247 // the if-block so that `Code` is not released after the if-block.
248 std::unique_ptr<llvm::MemoryBuffer> Code;
249 if (STDINMode) {
250 assert(options.getSourcePathList().size() == 1 &&
251 "Expect exactly one file path in STDINMode.");
252 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CodeOrErr =
253 MemoryBuffer::getSTDIN();
254 if (std::error_code EC = CodeOrErr.getError()) {
255 errs() << EC.message() << "\n";
256 return 1;
257 }
258 Code = std::move(CodeOrErr.get());
259 if (Code->getBufferSize() == 0)
260 return 0; // Skip empty files.
261
Haojian Wucd637012016-09-07 16:34:35 +0000262 tool.mapVirtualFile(SourceFilePath, Code->getBuffer());
Eric Liuc7f3b102016-05-18 14:10:16 +0000263 }
264
Haojian Wu11e9bd22016-05-31 09:31:51 +0000265 if (!InsertHeader.empty()) {
266 if (!STDINMode) {
267 errs() << "Should be running in STDIN mode\n";
268 return 1;
269 }
270
Haojian Wu17a54e32016-06-01 11:43:10 +0000271 llvm::yaml::Input yin(InsertHeader);
272 IncludeFixerContext Context;
273 yin >> Context;
274
Haojian Wu68c34a02016-07-13 16:43:54 +0000275 const auto &HeaderInfos = Context.getHeaderInfos();
276 assert(!HeaderInfos.empty());
277 // We only accept one unique header.
278 // Check all elements in HeaderInfos have the same header.
279 bool IsUniqueHeader = std::equal(
280 HeaderInfos.begin()+1, HeaderInfos.end(), HeaderInfos.begin(),
281 [](const IncludeFixerContext::HeaderInfo &LHS,
282 const IncludeFixerContext::HeaderInfo &RHS) {
283 return LHS.Header == RHS.Header;
284 });
285 if (!IsUniqueHeader) {
286 errs() << "Expect exactly one unique header.\n";
Haojian Wu17a54e32016-06-01 11:43:10 +0000287 return 1;
288 }
289
Haojian Wu62aee522016-07-21 13:47:09 +0000290 // If a header has multiple symbols, we won't add the missing namespace
Haojian Wu68c34a02016-07-13 16:43:54 +0000291 // qualifiers because we don't know which one is exactly used.
292 //
293 // Check whether all elements in HeaderInfos have the same qualified name.
294 bool IsUniqueQualifiedName = std::equal(
295 HeaderInfos.begin() + 1, HeaderInfos.end(), HeaderInfos.begin(),
296 [](const IncludeFixerContext::HeaderInfo &LHS,
297 const IncludeFixerContext::HeaderInfo &RHS) {
298 return LHS.QualifiedName == RHS.QualifiedName;
299 });
Haojian Wuc99f7282016-08-09 08:26:19 +0000300 format::FormatStyle InsertStyle =
301 format::getStyle("file", Context.getFilePath(), Style);
Haojian Wu62aee522016-07-21 13:47:09 +0000302 auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
Haojian Wuc99f7282016-08-09 08:26:19 +0000303 Code->getBuffer(), Context, InsertStyle,
Haojian Wu62aee522016-07-21 13:47:09 +0000304 /*AddQualifiers=*/IsUniqueQualifiedName);
305 if (!Replacements) {
306 errs() << "Failed to create replacements: "
307 << llvm::toString(Replacements.takeError()) << "\n";
308 return 1;
309 }
310
Eric Liua452db42016-07-11 13:53:21 +0000311 auto ChangedCode =
312 tooling::applyAllReplacements(Code->getBuffer(), *Replacements);
313 if (!ChangedCode) {
314 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
315 return 1;
316 }
317 llvm::outs() << *ChangedCode;
Haojian Wu11e9bd22016-05-31 09:31:51 +0000318 return 0;
319 }
320
Eric Liu692aca62016-05-04 08:22:35 +0000321 // Set up data source.
Haojian Wueb6ce062016-05-31 13:23:00 +0000322 std::unique_ptr<include_fixer::SymbolIndexManager> SymbolIndexMgr =
Haojian Wucd637012016-09-07 16:34:35 +0000323 createSymbolIndexManager(SourceFilePath);
Haojian Wueb6ce062016-05-31 13:23:00 +0000324 if (!SymbolIndexMgr)
325 return 1;
Benjamin Kramer6b236262016-04-20 12:43:43 +0000326
Haojian Wucd637012016-09-07 16:34:35 +0000327 // Query symbol mode.
328 if (!QuerySymbol.empty()) {
329 auto MatchedSymbols = SymbolIndexMgr->search(QuerySymbol);
330 for (auto &Symbol : MatchedSymbols) {
331 std::string HeaderPath = Symbol.getFilePath().str();
332 Symbol.SetFilePath(((HeaderPath[0] == '"' || HeaderPath[0] == '<')
333 ? HeaderPath
334 : "\"" + HeaderPath + "\""));
335 }
336
337 // We leave an empty symbol range as we don't know the range of the symbol
338 // being queried in this mode. include-fixer won't add namespace qualifiers
339 // if the symbol range is empty, which also fits this case.
340 IncludeFixerContext::QuerySymbolInfo Symbol;
341 Symbol.RawIdentifier = QuerySymbol;
342 auto Context =
343 IncludeFixerContext(SourceFilePath, {Symbol}, MatchedSymbols);
344 writeToJson(llvm::outs(), Context);
345 return 0;
346 }
347
Benjamin Kramer6b236262016-04-20 12:43:43 +0000348 // Now run our tool.
Haojian Wuc99f7282016-08-09 08:26:19 +0000349 std::vector<include_fixer::IncludeFixerContext> Contexts;
350 include_fixer::IncludeFixerActionFactory Factory(*SymbolIndexMgr, Contexts,
Haojian Wu11e9bd22016-05-31 09:31:51 +0000351 Style, MinimizeIncludePaths);
Benjamin Kramer6b236262016-04-20 12:43:43 +0000352
Benjamin Kramer6b5160a2016-05-18 13:32:38 +0000353 if (tool.run(&Factory) != 0) {
354 llvm::errs()
355 << "Clang died with a fatal error! (incorrect include paths?)\n";
356 return 1;
357 }
Benjamin Kramer6b236262016-04-20 12:43:43 +0000358
Haojian Wuc99f7282016-08-09 08:26:19 +0000359 assert(!Contexts.empty());
360
Haojian Wu11e9bd22016-05-31 09:31:51 +0000361 if (OutputHeaders) {
Haojian Wuc99f7282016-08-09 08:26:19 +0000362 // FIXME: Print contexts of all processing files instead of the first one.
363 writeToJson(llvm::outs(), Contexts.front());
Haojian Wu11e9bd22016-05-31 09:31:51 +0000364 return 0;
365 }
366
Haojian Wuc99f7282016-08-09 08:26:19 +0000367 std::vector<tooling::Replacements> FixerReplacements;
368 for (const auto &Context : Contexts) {
369 StringRef FilePath = Context.getFilePath();
370 format::FormatStyle InsertStyle = format::getStyle("file", FilePath, Style);
371 auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
372 if (!Buffer) {
373 errs() << "Couldn't open file: " + FilePath.str() + ": "
374 << Buffer.getError().message() + "\n";
375 return 1;
376 }
Haojian Wu11e9bd22016-05-31 09:31:51 +0000377
Haojian Wuc99f7282016-08-09 08:26:19 +0000378 auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
379 Buffer.get()->getBuffer(), Context, InsertStyle);
380 if (!Replacements) {
381 errs() << "Failed to create replacement: "
382 << llvm::toString(Replacements.takeError()) << "\n";
383 return 1;
384 }
385 FixerReplacements.push_back(*Replacements);
Haojian Wu11e9bd22016-05-31 09:31:51 +0000386 }
387
Haojian Wuc99f7282016-08-09 08:26:19 +0000388 if (!Quiet) {
389 for (const auto &Context : Contexts) {
390 if (!Context.getHeaderInfos().empty()) {
391 llvm::errs() << "Added #include "
392 << Context.getHeaderInfos().front().Header << " for "
393 << Context.getFilePath() << "\n";
394 }
395 }
Eric Liua452db42016-07-11 13:53:21 +0000396 }
Haojian Wu11e9bd22016-05-31 09:31:51 +0000397
Eric Liuc7f3b102016-05-18 14:10:16 +0000398 if (STDINMode) {
Haojian Wuc99f7282016-08-09 08:26:19 +0000399 assert(FixerReplacements.size() == 1);
400 auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(),
401 FixerReplacements.front());
Eric Liua452db42016-07-11 13:53:21 +0000402 if (!ChangedCode) {
403 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
404 return 1;
405 }
406 llvm::outs() << *ChangedCode;
Eric Liuc7f3b102016-05-18 14:10:16 +0000407 return 0;
408 }
409
Haojian Wuc99f7282016-08-09 08:26:19 +0000410 // Set up a new source manager for applying the resulting replacements.
411 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
412 DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
413 TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
414 SourceManager SM(Diagnostics, tool.getFiles());
415 Diagnostics.setClient(&DiagnosticPrinter, false);
416
Benjamin Kramer6b236262016-04-20 12:43:43 +0000417 // Write replacements to disk.
Benjamin Kramerf412e902016-04-27 14:24:32 +0000418 Rewriter Rewrites(SM, LangOptions());
Benjamin Kramer089a39e2016-10-19 13:50:17 +0000419 for (const auto &Replacement : FixerReplacements) {
Haojian Wuc99f7282016-08-09 08:26:19 +0000420 if (!tooling::applyAllReplacements(Replacement, Rewrites)) {
421 llvm::errs() << "Failed to apply replacements.\n";
422 return 1;
423 }
424 }
Benjamin Kramer6b236262016-04-20 12:43:43 +0000425 return Rewrites.overwriteChangedFiles();
426}
Haojian Wua315dcb2016-05-03 08:38:35 +0000427
428} // namespace
429
430int main(int argc, const char **argv) {
431 return includeFixerMain(argc, argv);
432}