1 //===--- ClangRefactor.cpp - Clang-based refactoring tool -----------------===//
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 /// \file
10 /// This file implements a clang-refactor tool that performs various
11 /// source transformations.
12 ///
13 //===----------------------------------------------------------------------===//
14
15 #include "TestSupport.h"
16 #include "clang/Frontend/CommandLineSourceLoc.h"
17 #include "clang/Frontend/TextDiagnosticPrinter.h"
18 #include "clang/Rewrite/Core/Rewriter.h"
19 #include "clang/Tooling/CommonOptionsParser.h"
20 #include "clang/Tooling/Refactoring.h"
21 #include "clang/Tooling/Refactoring/RefactoringAction.h"
22 #include "clang/Tooling/Refactoring/RefactoringOptions.h"
23 #include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
24 #include "clang/Tooling/Tooling.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/Signals.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include <string>
30
31 using namespace clang;
32 using namespace tooling;
33 using namespace refactor;
34 namespace cl = llvm::cl;
35
36 namespace opts {
37
38 static cl::OptionCategory CommonRefactorOptions("Refactoring options");
39
40 static cl::opt<bool> Verbose("v", cl::desc("Use verbose output"),
41 cl::cat(cl::GeneralCategory),
42 cl::sub(*cl::AllSubCommands));
43
44 static cl::opt<bool> Inplace("i", cl::desc("Inplace edit <file>s"),
45 cl::cat(cl::GeneralCategory),
46 cl::sub(*cl::AllSubCommands));
47
48 } // end namespace opts
49
50 namespace {
51
52 /// Stores the parsed `-selection` argument.
53 class SourceSelectionArgument {
54 public:
~SourceSelectionArgument()55 virtual ~SourceSelectionArgument() {}
56
57 /// Parse the `-selection` argument.
58 ///
59 /// \returns A valid argument when the parse succedeed, null otherwise.
60 static std::unique_ptr<SourceSelectionArgument> fromString(StringRef Value);
61
62 /// Prints any additional state associated with the selection argument to
63 /// the given output stream.
print(raw_ostream & OS)64 virtual void print(raw_ostream &OS) {}
65
66 /// Returns a replacement refactoring result consumer (if any) that should
67 /// consume the results of a refactoring operation.
68 ///
69 /// The replacement refactoring result consumer is used by \c
70 /// TestSourceSelectionArgument to inject a test-specific result handling
71 /// logic into the refactoring operation. The test-specific consumer
72 /// ensures that the individual results in a particular test group are
73 /// identical.
74 virtual std::unique_ptr<ClangRefactorToolConsumerInterface>
createCustomConsumer()75 createCustomConsumer() {
76 return nullptr;
77 }
78
79 /// Runs the give refactoring function for each specified selection.
80 ///
81 /// \returns true if an error occurred, false otherwise.
82 virtual bool
83 forAllRanges(const SourceManager &SM,
84 llvm::function_ref<void(SourceRange R)> Callback) = 0;
85 };
86
87 /// Stores the parsed -selection=test:<filename> option.
88 class TestSourceSelectionArgument final : public SourceSelectionArgument {
89 public:
TestSourceSelectionArgument(TestSelectionRangesInFile TestSelections)90 TestSourceSelectionArgument(TestSelectionRangesInFile TestSelections)
91 : TestSelections(std::move(TestSelections)) {}
92
print(raw_ostream & OS)93 void print(raw_ostream &OS) override { TestSelections.dump(OS); }
94
95 std::unique_ptr<ClangRefactorToolConsumerInterface>
createCustomConsumer()96 createCustomConsumer() override {
97 return TestSelections.createConsumer();
98 }
99
100 /// Testing support: invokes the selection action for each selection range in
101 /// the test file.
forAllRanges(const SourceManager & SM,llvm::function_ref<void (SourceRange R)> Callback)102 bool forAllRanges(const SourceManager &SM,
103 llvm::function_ref<void(SourceRange R)> Callback) override {
104 return TestSelections.foreachRange(SM, Callback);
105 }
106
107 private:
108 TestSelectionRangesInFile TestSelections;
109 };
110
111 /// Stores the parsed -selection=filename:line:column[-line:column] option.
112 class SourceRangeSelectionArgument final : public SourceSelectionArgument {
113 public:
SourceRangeSelectionArgument(ParsedSourceRange Range)114 SourceRangeSelectionArgument(ParsedSourceRange Range)
115 : Range(std::move(Range)) {}
116
forAllRanges(const SourceManager & SM,llvm::function_ref<void (SourceRange R)> Callback)117 bool forAllRanges(const SourceManager &SM,
118 llvm::function_ref<void(SourceRange R)> Callback) override {
119 auto FE = SM.getFileManager().getFile(Range.FileName);
120 FileID FID = FE ? SM.translateFile(*FE) : FileID();
121 if (!FE || FID.isInvalid()) {
122 llvm::errs() << "error: -selection=" << Range.FileName
123 << ":... : given file is not in the target TU\n";
124 return true;
125 }
126
127 SourceLocation Start = SM.getMacroArgExpandedLocation(
128 SM.translateLineCol(FID, Range.Begin.first, Range.Begin.second));
129 SourceLocation End = SM.getMacroArgExpandedLocation(
130 SM.translateLineCol(FID, Range.End.first, Range.End.second));
131 if (Start.isInvalid() || End.isInvalid()) {
132 llvm::errs() << "error: -selection=" << Range.FileName << ':'
133 << Range.Begin.first << ':' << Range.Begin.second << '-'
134 << Range.End.first << ':' << Range.End.second
135 << " : invalid source location\n";
136 return true;
137 }
138 Callback(SourceRange(Start, End));
139 return false;
140 }
141
142 private:
143 ParsedSourceRange Range;
144 };
145
146 std::unique_ptr<SourceSelectionArgument>
fromString(StringRef Value)147 SourceSelectionArgument::fromString(StringRef Value) {
148 if (Value.startswith("test:")) {
149 StringRef Filename = Value.drop_front(strlen("test:"));
150 Optional<TestSelectionRangesInFile> ParsedTestSelection =
151 findTestSelectionRanges(Filename);
152 if (!ParsedTestSelection)
153 return nullptr; // A parsing error was already reported.
154 return std::make_unique<TestSourceSelectionArgument>(
155 std::move(*ParsedTestSelection));
156 }
157 Optional<ParsedSourceRange> Range = ParsedSourceRange::fromString(Value);
158 if (Range)
159 return std::make_unique<SourceRangeSelectionArgument>(std::move(*Range));
160 llvm::errs() << "error: '-selection' option must be specified using "
161 "<file>:<line>:<column> or "
162 "<file>:<line>:<column>-<line>:<column> format\n";
163 return nullptr;
164 }
165
166 /// A container that stores the command-line options used by a single
167 /// refactoring option.
168 class RefactoringActionCommandLineOptions {
169 public:
addStringOption(const RefactoringOption & Option,std::unique_ptr<cl::opt<std::string>> CLOption)170 void addStringOption(const RefactoringOption &Option,
171 std::unique_ptr<cl::opt<std::string>> CLOption) {
172 StringOptions[&Option] = std::move(CLOption);
173 }
174
175 const cl::opt<std::string> &
getStringOption(const RefactoringOption & Opt) const176 getStringOption(const RefactoringOption &Opt) const {
177 auto It = StringOptions.find(&Opt);
178 return *It->second;
179 }
180
181 private:
182 llvm::DenseMap<const RefactoringOption *,
183 std::unique_ptr<cl::opt<std::string>>>
184 StringOptions;
185 };
186
187 /// Passes the command-line option values to the options used by a single
188 /// refactoring action rule.
189 class CommandLineRefactoringOptionVisitor final
190 : public RefactoringOptionVisitor {
191 public:
CommandLineRefactoringOptionVisitor(const RefactoringActionCommandLineOptions & Options)192 CommandLineRefactoringOptionVisitor(
193 const RefactoringActionCommandLineOptions &Options)
194 : Options(Options) {}
195
visit(const RefactoringOption & Opt,Optional<std::string> & Value)196 void visit(const RefactoringOption &Opt,
197 Optional<std::string> &Value) override {
198 const cl::opt<std::string> &CLOpt = Options.getStringOption(Opt);
199 if (!CLOpt.getValue().empty()) {
200 Value = CLOpt.getValue();
201 return;
202 }
203 Value = None;
204 if (Opt.isRequired())
205 MissingRequiredOptions.push_back(&Opt);
206 }
207
getMissingRequiredOptions() const208 ArrayRef<const RefactoringOption *> getMissingRequiredOptions() const {
209 return MissingRequiredOptions;
210 }
211
212 private:
213 llvm::SmallVector<const RefactoringOption *, 4> MissingRequiredOptions;
214 const RefactoringActionCommandLineOptions &Options;
215 };
216
217 /// Creates the refactoring options used by all the rules in a single
218 /// refactoring action.
219 class CommandLineRefactoringOptionCreator final
220 : public RefactoringOptionVisitor {
221 public:
CommandLineRefactoringOptionCreator(cl::OptionCategory & Category,cl::SubCommand & Subcommand,RefactoringActionCommandLineOptions & Options)222 CommandLineRefactoringOptionCreator(
223 cl::OptionCategory &Category, cl::SubCommand &Subcommand,
224 RefactoringActionCommandLineOptions &Options)
225 : Category(Category), Subcommand(Subcommand), Options(Options) {}
226
visit(const RefactoringOption & Opt,Optional<std::string> &)227 void visit(const RefactoringOption &Opt, Optional<std::string> &) override {
228 if (Visited.insert(&Opt).second)
229 Options.addStringOption(Opt, create<std::string>(Opt));
230 }
231
232 private:
233 template <typename T>
create(const RefactoringOption & Opt)234 std::unique_ptr<cl::opt<T>> create(const RefactoringOption &Opt) {
235 if (!OptionNames.insert(Opt.getName()).second)
236 llvm::report_fatal_error("Multiple identical refactoring options "
237 "specified for one refactoring action");
238 // FIXME: cl::Required can be specified when this option is present
239 // in all rules in an action.
240 return std::make_unique<cl::opt<T>>(
241 Opt.getName(), cl::desc(Opt.getDescription()), cl::Optional,
242 cl::cat(Category), cl::sub(Subcommand));
243 }
244
245 llvm::SmallPtrSet<const RefactoringOption *, 8> Visited;
246 llvm::StringSet<> OptionNames;
247 cl::OptionCategory &Category;
248 cl::SubCommand &Subcommand;
249 RefactoringActionCommandLineOptions &Options;
250 };
251
252 /// A subcommand that corresponds to individual refactoring action.
253 class RefactoringActionSubcommand : public cl::SubCommand {
254 public:
RefactoringActionSubcommand(std::unique_ptr<RefactoringAction> Action,RefactoringActionRules ActionRules,cl::OptionCategory & Category)255 RefactoringActionSubcommand(std::unique_ptr<RefactoringAction> Action,
256 RefactoringActionRules ActionRules,
257 cl::OptionCategory &Category)
258 : SubCommand(Action->getCommand(), Action->getDescription()),
259 Action(std::move(Action)), ActionRules(std::move(ActionRules)) {
260 // Check if the selection option is supported.
261 for (const auto &Rule : this->ActionRules) {
262 if (Rule->hasSelectionRequirement()) {
263 Selection = std::make_unique<cl::opt<std::string>>(
264 "selection",
265 cl::desc(
266 "The selected source range in which the refactoring should "
267 "be initiated (<file>:<line>:<column>-<line>:<column> or "
268 "<file>:<line>:<column>)"),
269 cl::cat(Category), cl::sub(*this));
270 break;
271 }
272 }
273 // Create the refactoring options.
274 for (const auto &Rule : this->ActionRules) {
275 CommandLineRefactoringOptionCreator OptionCreator(Category, *this,
276 Options);
277 Rule->visitRefactoringOptions(OptionCreator);
278 }
279 }
280
~RefactoringActionSubcommand()281 ~RefactoringActionSubcommand() { unregisterSubCommand(); }
282
getActionRules() const283 const RefactoringActionRules &getActionRules() const { return ActionRules; }
284
285 /// Parses the "-selection" command-line argument.
286 ///
287 /// \returns true on error, false otherwise.
parseSelectionArgument()288 bool parseSelectionArgument() {
289 if (Selection) {
290 ParsedSelection = SourceSelectionArgument::fromString(*Selection);
291 if (!ParsedSelection)
292 return true;
293 }
294 return false;
295 }
296
getSelection() const297 SourceSelectionArgument *getSelection() const {
298 assert(Selection && "selection not supported!");
299 return ParsedSelection.get();
300 }
301
getOptions() const302 const RefactoringActionCommandLineOptions &getOptions() const {
303 return Options;
304 }
305
306 private:
307 std::unique_ptr<RefactoringAction> Action;
308 RefactoringActionRules ActionRules;
309 std::unique_ptr<cl::opt<std::string>> Selection;
310 std::unique_ptr<SourceSelectionArgument> ParsedSelection;
311 RefactoringActionCommandLineOptions Options;
312 };
313
314 class ClangRefactorConsumer final : public ClangRefactorToolConsumerInterface {
315 public:
ClangRefactorConsumer(AtomicChanges & Changes)316 ClangRefactorConsumer(AtomicChanges &Changes) : SourceChanges(&Changes) {}
317
handleError(llvm::Error Err)318 void handleError(llvm::Error Err) override {
319 Optional<PartialDiagnosticAt> Diag = DiagnosticError::take(Err);
320 if (!Diag) {
321 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
322 return;
323 }
324 llvm::cantFail(std::move(Err)); // This is a success.
325 DiagnosticBuilder DB(
326 getDiags().Report(Diag->first, Diag->second.getDiagID()));
327 Diag->second.Emit(DB);
328 }
329
handle(AtomicChanges Changes)330 void handle(AtomicChanges Changes) override {
331 SourceChanges->insert(SourceChanges->begin(), Changes.begin(),
332 Changes.end());
333 }
334
handle(SymbolOccurrences Occurrences)335 void handle(SymbolOccurrences Occurrences) override {
336 llvm_unreachable("symbol occurrence results are not handled yet");
337 }
338
339 private:
340 AtomicChanges *SourceChanges;
341 };
342
343 class ClangRefactorTool {
344 public:
ClangRefactorTool()345 ClangRefactorTool()
346 : SelectedSubcommand(nullptr), MatchingRule(nullptr),
347 Consumer(new ClangRefactorConsumer(Changes)), HasFailed(false) {
348 std::vector<std::unique_ptr<RefactoringAction>> Actions =
349 createRefactoringActions();
350
351 // Actions must have unique command names so that we can map them to one
352 // subcommand.
353 llvm::StringSet<> CommandNames;
354 for (const auto &Action : Actions) {
355 if (!CommandNames.insert(Action->getCommand()).second) {
356 llvm::errs() << "duplicate refactoring action command '"
357 << Action->getCommand() << "'!";
358 exit(1);
359 }
360 }
361
362 // Create subcommands and command-line options.
363 for (auto &Action : Actions) {
364 SubCommands.push_back(std::make_unique<RefactoringActionSubcommand>(
365 std::move(Action), Action->createActiveActionRules(),
366 opts::CommonRefactorOptions));
367 }
368 }
369
370 // Initializes the selected subcommand and refactoring rule based on the
371 // command line options.
Init()372 llvm::Error Init() {
373 auto Subcommand = getSelectedSubcommand();
374 if (!Subcommand)
375 return Subcommand.takeError();
376 auto Rule = getMatchingRule(**Subcommand);
377 if (!Rule)
378 return Rule.takeError();
379
380 SelectedSubcommand = *Subcommand;
381 MatchingRule = *Rule;
382
383 return llvm::Error::success();
384 }
385
hasFailed() const386 bool hasFailed() const { return HasFailed; }
387
388 using TUCallbackType = std::function<void(ASTContext &)>;
389
390 // Callback of an AST action. This invokes the matching rule on the given AST.
callback(ASTContext & AST)391 void callback(ASTContext &AST) {
392 assert(SelectedSubcommand && MatchingRule && Consumer);
393 RefactoringRuleContext Context(AST.getSourceManager());
394 Context.setASTContext(AST);
395
396 // If the selection option is test specific, we use a test-specific
397 // consumer.
398 std::unique_ptr<ClangRefactorToolConsumerInterface> TestConsumer;
399 bool HasSelection = MatchingRule->hasSelectionRequirement();
400 if (HasSelection)
401 TestConsumer = SelectedSubcommand->getSelection()->createCustomConsumer();
402 ClangRefactorToolConsumerInterface *ActiveConsumer =
403 TestConsumer ? TestConsumer.get() : Consumer.get();
404 ActiveConsumer->beginTU(AST);
405
406 auto InvokeRule = [&](RefactoringResultConsumer &Consumer) {
407 if (opts::Verbose)
408 logInvocation(*SelectedSubcommand, Context);
409 MatchingRule->invoke(*ActiveConsumer, Context);
410 };
411 if (HasSelection) {
412 assert(SelectedSubcommand->getSelection() &&
413 "Missing selection argument?");
414 if (opts::Verbose)
415 SelectedSubcommand->getSelection()->print(llvm::outs());
416 if (SelectedSubcommand->getSelection()->forAllRanges(
417 Context.getSources(), [&](SourceRange R) {
418 Context.setSelectionRange(R);
419 InvokeRule(*ActiveConsumer);
420 }))
421 HasFailed = true;
422 ActiveConsumer->endTU();
423 return;
424 }
425 InvokeRule(*ActiveConsumer);
426 ActiveConsumer->endTU();
427 }
428
429 llvm::Expected<std::unique_ptr<FrontendActionFactory>>
getFrontendActionFactory()430 getFrontendActionFactory() {
431 class ToolASTConsumer : public ASTConsumer {
432 public:
433 TUCallbackType Callback;
434 ToolASTConsumer(TUCallbackType Callback)
435 : Callback(std::move(Callback)) {}
436
437 void HandleTranslationUnit(ASTContext &Context) override {
438 Callback(Context);
439 }
440 };
441 class ToolASTAction : public ASTFrontendAction {
442 public:
443 explicit ToolASTAction(TUCallbackType Callback)
444 : Callback(std::move(Callback)) {}
445
446 protected:
447 std::unique_ptr<clang::ASTConsumer>
448 CreateASTConsumer(clang::CompilerInstance &compiler,
449 StringRef /* dummy */) override {
450 std::unique_ptr<clang::ASTConsumer> Consumer{
451 new ToolASTConsumer(Callback)};
452 return Consumer;
453 }
454
455 private:
456 TUCallbackType Callback;
457 };
458
459 class ToolActionFactory : public FrontendActionFactory {
460 public:
461 ToolActionFactory(TUCallbackType Callback)
462 : Callback(std::move(Callback)) {}
463
464 std::unique_ptr<FrontendAction> create() override {
465 return std::make_unique<ToolASTAction>(Callback);
466 }
467
468 private:
469 TUCallbackType Callback;
470 };
471
472 return std::make_unique<ToolActionFactory>(
473 [this](ASTContext &AST) { return callback(AST); });
474 }
475
476 // FIXME(ioeric): this seems to only works for changes in a single file at
477 // this point.
applySourceChanges()478 bool applySourceChanges() {
479 std::set<std::string> Files;
480 for (const auto &Change : Changes)
481 Files.insert(Change.getFilePath());
482 // FIXME: Add automatic formatting support as well.
483 tooling::ApplyChangesSpec Spec;
484 // FIXME: We should probably cleanup the result by default as well.
485 Spec.Cleanup = false;
486 for (const auto &File : Files) {
487 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
488 llvm::MemoryBuffer::getFile(File);
489 if (!BufferErr) {
490 llvm::errs() << "error: failed to open " << File << " for rewriting\n";
491 return true;
492 }
493 auto Result = tooling::applyAtomicChanges(File, (*BufferErr)->getBuffer(),
494 Changes, Spec);
495 if (!Result) {
496 llvm::errs() << toString(Result.takeError());
497 return true;
498 }
499
500 if (opts::Inplace) {
501 std::error_code EC;
502 llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::OF_Text);
503 if (EC) {
504 llvm::errs() << EC.message() << "\n";
505 return true;
506 }
507 OS << *Result;
508 continue;
509 }
510
511 llvm::outs() << *Result;
512 }
513 return false;
514 }
515
516 private:
517 /// Logs an individual refactoring action invocation to STDOUT.
logInvocation(RefactoringActionSubcommand & Subcommand,const RefactoringRuleContext & Context)518 void logInvocation(RefactoringActionSubcommand &Subcommand,
519 const RefactoringRuleContext &Context) {
520 llvm::outs() << "invoking action '" << Subcommand.getName() << "':\n";
521 if (Context.getSelectionRange().isValid()) {
522 SourceRange R = Context.getSelectionRange();
523 llvm::outs() << " -selection=";
524 R.getBegin().print(llvm::outs(), Context.getSources());
525 llvm::outs() << " -> ";
526 R.getEnd().print(llvm::outs(), Context.getSources());
527 llvm::outs() << "\n";
528 }
529 }
530
531 llvm::Expected<RefactoringActionRule *>
getMatchingRule(RefactoringActionSubcommand & Subcommand)532 getMatchingRule(RefactoringActionSubcommand &Subcommand) {
533 SmallVector<RefactoringActionRule *, 4> MatchingRules;
534 llvm::StringSet<> MissingOptions;
535
536 for (const auto &Rule : Subcommand.getActionRules()) {
537 CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
538 Rule->visitRefactoringOptions(Visitor);
539 if (Visitor.getMissingRequiredOptions().empty()) {
540 if (!Rule->hasSelectionRequirement()) {
541 MatchingRules.push_back(Rule.get());
542 } else {
543 Subcommand.parseSelectionArgument();
544 if (Subcommand.getSelection()) {
545 MatchingRules.push_back(Rule.get());
546 } else {
547 MissingOptions.insert("selection");
548 }
549 }
550 }
551 for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
552 MissingOptions.insert(Opt->getName());
553 }
554 if (MatchingRules.empty()) {
555 std::string Error;
556 llvm::raw_string_ostream OS(Error);
557 OS << "ERROR: '" << Subcommand.getName()
558 << "' can't be invoked with the given arguments:\n";
559 for (const auto &Opt : MissingOptions)
560 OS << " missing '-" << Opt.getKey() << "' option\n";
561 OS.flush();
562 return llvm::make_error<llvm::StringError>(
563 Error, llvm::inconvertibleErrorCode());
564 }
565 if (MatchingRules.size() != 1) {
566 return llvm::make_error<llvm::StringError>(
567 llvm::Twine("ERROR: more than one matching rule of action") +
568 Subcommand.getName() + "was found with given options.",
569 llvm::inconvertibleErrorCode());
570 }
571 return MatchingRules.front();
572 }
573 // Figure out which action is specified by the user. The user must specify the
574 // action using a command-line subcommand, e.g. the invocation `clang-refactor
575 // local-rename` corresponds to the `LocalRename` refactoring action. All
576 // subcommands must have a unique names. This allows us to figure out which
577 // refactoring action should be invoked by looking at the first subcommand
578 // that's enabled by LLVM's command-line parser.
getSelectedSubcommand()579 llvm::Expected<RefactoringActionSubcommand *> getSelectedSubcommand() {
580 auto It = llvm::find_if(
581 SubCommands,
582 [](const std::unique_ptr<RefactoringActionSubcommand> &SubCommand) {
583 return !!(*SubCommand);
584 });
585 if (It == SubCommands.end()) {
586 std::string Error;
587 llvm::raw_string_ostream OS(Error);
588 OS << "error: no refactoring action given\n";
589 OS << "note: the following actions are supported:\n";
590 for (const auto &Subcommand : SubCommands)
591 OS.indent(2) << Subcommand->getName() << "\n";
592 OS.flush();
593 return llvm::make_error<llvm::StringError>(
594 Error, llvm::inconvertibleErrorCode());
595 }
596 RefactoringActionSubcommand *Subcommand = &(**It);
597 return Subcommand;
598 }
599
600 std::vector<std::unique_ptr<RefactoringActionSubcommand>> SubCommands;
601 RefactoringActionSubcommand *SelectedSubcommand;
602 RefactoringActionRule *MatchingRule;
603 std::unique_ptr<ClangRefactorToolConsumerInterface> Consumer;
604 AtomicChanges Changes;
605 bool HasFailed;
606 };
607
608 } // end anonymous namespace
609
main(int argc,const char ** argv)610 int main(int argc, const char **argv) {
611 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
612
613 ClangRefactorTool RefactorTool;
614
615 CommonOptionsParser Options(
616 argc, argv, cl::GeneralCategory, cl::ZeroOrMore,
617 "Clang-based refactoring tool for C, C++ and Objective-C");
618
619 if (auto Err = RefactorTool.Init()) {
620 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
621 return 1;
622 }
623
624 auto ActionFactory = RefactorTool.getFrontendActionFactory();
625 if (!ActionFactory) {
626 llvm::errs() << llvm::toString(ActionFactory.takeError()) << "\n";
627 return 1;
628 }
629 ClangTool Tool(Options.getCompilations(), Options.getSourcePathList());
630 bool Failed = false;
631 if (Tool.run(ActionFactory->get()) != 0) {
632 llvm::errs() << "Failed to run refactoring action on files\n";
633 // It is possible that TUs are broken while changes are generated correctly,
634 // so we still try applying changes.
635 Failed = true;
636 }
637 return RefactorTool.applySourceChanges() || Failed ||
638 RefactorTool.hasFailed();
639 }
640