blob: 800729db86195543b56281789be5b08673fe59d9 [file] [log] [blame]
Alex Lorenzb54ef6a2017-09-14 10:06:52 +00001//===--- ClangRefactor.cpp - Clang-based refactoring tool -----------------===//
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///
10/// \file
11/// \brief This file implements a clang-refactor tool that performs various
12/// source transformations.
13///
14//===----------------------------------------------------------------------===//
15
16#include "TestSupport.h"
Alex Lorenze1b7b952017-10-16 17:31:16 +000017#include "clang/Frontend/CommandLineSourceLoc.h"
Alex Lorenzb54ef6a2017-09-14 10:06:52 +000018#include "clang/Rewrite/Core/Rewriter.h"
Alex Lorenz3d712c42017-09-14 13:16:14 +000019#include "clang/Tooling/CommonOptionsParser.h"
Alex Lorenzb54ef6a2017-09-14 10:06:52 +000020#include "clang/Tooling/Refactoring.h"
21#include "clang/Tooling/Refactoring/RefactoringAction.h"
Alex Lorenzad38fbf2017-10-13 01:53:13 +000022#include "clang/Tooling/Refactoring/RefactoringOptions.h"
Alex Lorenzb54ef6a2017-09-14 10:06:52 +000023#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/raw_ostream.h"
28#include <string>
29
30using namespace clang;
31using namespace tooling;
32using namespace refactor;
33namespace cl = llvm::cl;
34
35namespace opts {
36
Alex Lorenzad38fbf2017-10-13 01:53:13 +000037static cl::OptionCategory CommonRefactorOptions("Refactoring options");
Alex Lorenzb54ef6a2017-09-14 10:06:52 +000038
Alex Lorenzb54ef6a2017-09-14 10:06:52 +000039static cl::opt<bool> Verbose("v", cl::desc("Use verbose output"),
Alex Lorenzad38fbf2017-10-13 01:53:13 +000040 cl::cat(cl::GeneralCategory),
Alex Lorenzb54ef6a2017-09-14 10:06:52 +000041 cl::sub(*cl::AllSubCommands));
42} // end namespace opts
43
44namespace {
45
46/// Stores the parsed `-selection` argument.
47class SourceSelectionArgument {
48public:
49 virtual ~SourceSelectionArgument() {}
50
51 /// Parse the `-selection` argument.
52 ///
53 /// \returns A valid argument when the parse succedeed, null otherwise.
54 static std::unique_ptr<SourceSelectionArgument> fromString(StringRef Value);
55
56 /// Prints any additional state associated with the selection argument to
57 /// the given output stream.
Alex Lorenze1b7b952017-10-16 17:31:16 +000058 virtual void print(raw_ostream &OS) {}
Alex Lorenzb54ef6a2017-09-14 10:06:52 +000059
60 /// Returns a replacement refactoring result consumer (if any) that should
61 /// consume the results of a refactoring operation.
62 ///
63 /// The replacement refactoring result consumer is used by \c
64 /// TestSourceSelectionArgument to inject a test-specific result handling
65 /// logic into the refactoring operation. The test-specific consumer
66 /// ensures that the individual results in a particular test group are
67 /// identical.
68 virtual std::unique_ptr<RefactoringResultConsumer> createCustomConsumer() {
69 return nullptr;
70 }
71
72 /// Runs the give refactoring function for each specified selection.
73 ///
74 /// \returns true if an error occurred, false otherwise.
75 virtual bool
76 forAllRanges(const SourceManager &SM,
77 llvm::function_ref<void(SourceRange R)> Callback) = 0;
78};
79
80/// Stores the parsed -selection=test:<filename> option.
81class TestSourceSelectionArgument final : public SourceSelectionArgument {
82public:
83 TestSourceSelectionArgument(TestSelectionRangesInFile TestSelections)
84 : TestSelections(std::move(TestSelections)) {}
85
86 void print(raw_ostream &OS) override { TestSelections.dump(OS); }
87
88 std::unique_ptr<RefactoringResultConsumer> createCustomConsumer() override {
89 return TestSelections.createConsumer();
90 }
91
92 /// Testing support: invokes the selection action for each selection range in
93 /// the test file.
94 bool forAllRanges(const SourceManager &SM,
95 llvm::function_ref<void(SourceRange R)> Callback) override {
96 return TestSelections.foreachRange(SM, Callback);
97 }
98
99private:
100 TestSelectionRangesInFile TestSelections;
101};
102
Alex Lorenze1b7b952017-10-16 17:31:16 +0000103/// Stores the parsed -selection=filename:line:column[-line:column] option.
104class SourceRangeSelectionArgument final : public SourceSelectionArgument {
105public:
106 SourceRangeSelectionArgument(ParsedSourceRange Range)
107 : Range(std::move(Range)) {}
108
109 bool forAllRanges(const SourceManager &SM,
110 llvm::function_ref<void(SourceRange R)> Callback) override {
111 const FileEntry *FE = SM.getFileManager().getFile(Range.FileName);
112 FileID FID = FE ? SM.translateFile(FE) : FileID();
113 if (!FE || FID.isInvalid()) {
114 llvm::errs() << "error: -selection=" << Range.FileName
115 << ":... : given file is not in the target TU\n";
116 return true;
117 }
118
119 SourceLocation Start = SM.getMacroArgExpandedLocation(
120 SM.translateLineCol(FID, Range.Begin.first, Range.Begin.second));
121 SourceLocation End = SM.getMacroArgExpandedLocation(
122 SM.translateLineCol(FID, Range.End.first, Range.End.second));
123 if (Start.isInvalid() || End.isInvalid()) {
124 llvm::errs() << "error: -selection=" << Range.FileName << ':'
125 << Range.Begin.first << ':' << Range.Begin.second << '-'
126 << Range.End.first << ':' << Range.End.second
127 << " : invalid source location\n";
128 return true;
129 }
130 Callback(SourceRange(Start, End));
131 return false;
132 }
133
134private:
135 ParsedSourceRange Range;
136};
137
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000138std::unique_ptr<SourceSelectionArgument>
139SourceSelectionArgument::fromString(StringRef Value) {
140 if (Value.startswith("test:")) {
141 StringRef Filename = Value.drop_front(strlen("test:"));
142 Optional<TestSelectionRangesInFile> ParsedTestSelection =
143 findTestSelectionRanges(Filename);
144 if (!ParsedTestSelection)
145 return nullptr; // A parsing error was already reported.
146 return llvm::make_unique<TestSourceSelectionArgument>(
147 std::move(*ParsedTestSelection));
148 }
Alex Lorenze1b7b952017-10-16 17:31:16 +0000149 Optional<ParsedSourceRange> Range = ParsedSourceRange::fromString(Value);
150 if (Range)
151 return llvm::make_unique<SourceRangeSelectionArgument>(std::move(*Range));
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000152 llvm::errs() << "error: '-selection' option must be specified using "
153 "<file>:<line>:<column> or "
Alex Lorenze1b7b952017-10-16 17:31:16 +0000154 "<file>:<line>:<column>-<line>:<column> format\n";
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000155 return nullptr;
156}
157
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000158/// A container that stores the command-line options used by a single
159/// refactoring option.
160class RefactoringActionCommandLineOptions {
161public:
162 void addStringOption(const RefactoringOption &Option,
163 std::unique_ptr<cl::opt<std::string>> CLOption) {
164 StringOptions[&Option] = std::move(CLOption);
165 }
166
167 const cl::opt<std::string> &
168 getStringOption(const RefactoringOption &Opt) const {
169 auto It = StringOptions.find(&Opt);
170 return *It->second;
171 }
172
173private:
174 llvm::DenseMap<const RefactoringOption *,
175 std::unique_ptr<cl::opt<std::string>>>
176 StringOptions;
177};
178
179/// Passes the command-line option values to the options used by a single
180/// refactoring action rule.
181class CommandLineRefactoringOptionVisitor final
182 : public RefactoringOptionVisitor {
183public:
184 CommandLineRefactoringOptionVisitor(
185 const RefactoringActionCommandLineOptions &Options)
186 : Options(Options) {}
187
188 void visit(const RefactoringOption &Opt,
189 Optional<std::string> &Value) override {
190 const cl::opt<std::string> &CLOpt = Options.getStringOption(Opt);
191 if (!CLOpt.getValue().empty()) {
192 Value = CLOpt.getValue();
193 return;
194 }
195 Value = None;
196 if (Opt.isRequired())
197 MissingRequiredOptions.push_back(&Opt);
198 }
199
200 ArrayRef<const RefactoringOption *> getMissingRequiredOptions() const {
201 return MissingRequiredOptions;
202 }
203
204private:
205 llvm::SmallVector<const RefactoringOption *, 4> MissingRequiredOptions;
206 const RefactoringActionCommandLineOptions &Options;
207};
208
209/// Creates the refactoring options used by all the rules in a single
210/// refactoring action.
211class CommandLineRefactoringOptionCreator final
212 : public RefactoringOptionVisitor {
213public:
214 CommandLineRefactoringOptionCreator(
215 cl::OptionCategory &Category, cl::SubCommand &Subcommand,
216 RefactoringActionCommandLineOptions &Options)
217 : Category(Category), Subcommand(Subcommand), Options(Options) {}
218
219 void visit(const RefactoringOption &Opt, Optional<std::string> &) override {
220 if (Visited.insert(&Opt).second)
221 Options.addStringOption(Opt, create<std::string>(Opt));
222 }
223
224private:
225 template <typename T>
226 std::unique_ptr<cl::opt<T>> create(const RefactoringOption &Opt) {
227 if (!OptionNames.insert(Opt.getName()).second)
228 llvm::report_fatal_error("Multiple identical refactoring options "
229 "specified for one refactoring action");
230 // FIXME: cl::Required can be specified when this option is present
231 // in all rules in an action.
232 return llvm::make_unique<cl::opt<T>>(
233 Opt.getName(), cl::desc(Opt.getDescription()), cl::Optional,
234 cl::cat(Category), cl::sub(Subcommand));
235 }
236
237 llvm::SmallPtrSet<const RefactoringOption *, 8> Visited;
238 llvm::StringSet<> OptionNames;
239 cl::OptionCategory &Category;
240 cl::SubCommand &Subcommand;
241 RefactoringActionCommandLineOptions &Options;
242};
243
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000244/// A subcommand that corresponds to individual refactoring action.
245class RefactoringActionSubcommand : public cl::SubCommand {
246public:
247 RefactoringActionSubcommand(std::unique_ptr<RefactoringAction> Action,
248 RefactoringActionRules ActionRules,
249 cl::OptionCategory &Category)
250 : SubCommand(Action->getCommand(), Action->getDescription()),
251 Action(std::move(Action)), ActionRules(std::move(ActionRules)) {
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000252 // Check if the selection option is supported.
253 bool HasSelection = false;
254 for (const auto &Rule : this->ActionRules) {
255 if ((HasSelection = Rule->hasSelectionRequirement()))
256 break;
257 }
258 if (HasSelection) {
259 Selection = llvm::make_unique<cl::opt<std::string>>(
260 "selection",
261 cl::desc("The selected source range in which the refactoring should "
262 "be initiated (<file>:<line>:<column>-<line>:<column> or "
263 "<file>:<line>:<column>)"),
264 cl::cat(Category), cl::sub(*this));
265 }
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000266 // Create the refactoring options.
267 for (const auto &Rule : this->ActionRules) {
268 CommandLineRefactoringOptionCreator OptionCreator(Category, *this,
269 Options);
270 Rule->visitRefactoringOptions(OptionCreator);
271 }
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000272 }
273
274 ~RefactoringActionSubcommand() { unregisterSubCommand(); }
275
276 const RefactoringActionRules &getActionRules() const { return ActionRules; }
277
278 /// Parses the command-line arguments that are specific to this rule.
279 ///
280 /// \returns true on error, false otherwise.
281 bool parseArguments() {
282 if (Selection) {
283 ParsedSelection = SourceSelectionArgument::fromString(*Selection);
284 if (!ParsedSelection)
285 return true;
286 }
287 return false;
288 }
289
290 SourceSelectionArgument *getSelection() const {
291 assert(Selection && "selection not supported!");
292 return ParsedSelection.get();
293 }
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000294
295 const RefactoringActionCommandLineOptions &getOptions() const {
296 return Options;
297 }
298
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000299private:
300 std::unique_ptr<RefactoringAction> Action;
301 RefactoringActionRules ActionRules;
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000302 std::unique_ptr<cl::opt<std::string>> Selection;
303 std::unique_ptr<SourceSelectionArgument> ParsedSelection;
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000304 RefactoringActionCommandLineOptions Options;
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000305};
306
307class ClangRefactorConsumer : public RefactoringResultConsumer {
308public:
Alex Lorenze1b7b952017-10-16 17:31:16 +0000309 void handleError(llvm::Error Err) override {
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000310 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
311 }
312
Alex Lorenze1b7b952017-10-16 17:31:16 +0000313 void handle(AtomicChanges Changes) override {
314 SourceChanges.insert(SourceChanges.begin(), Changes.begin(), Changes.end());
315 }
316
317 void handle(SymbolOccurrences Occurrences) override {
318 RefactoringResultConsumer::handle(std::move(Occurrences));
319 }
320
321 const AtomicChanges &getSourceChanges() const { return SourceChanges; }
322
323private:
324 AtomicChanges SourceChanges;
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000325};
326
327class ClangRefactorTool {
328public:
329 std::vector<std::unique_ptr<RefactoringActionSubcommand>> SubCommands;
330
331 ClangRefactorTool() {
332 std::vector<std::unique_ptr<RefactoringAction>> Actions =
333 createRefactoringActions();
334
335 // Actions must have unique command names so that we can map them to one
336 // subcommand.
337 llvm::StringSet<> CommandNames;
338 for (const auto &Action : Actions) {
339 if (!CommandNames.insert(Action->getCommand()).second) {
340 llvm::errs() << "duplicate refactoring action command '"
341 << Action->getCommand() << "'!";
342 exit(1);
343 }
344 }
345
346 // Create subcommands and command-line options.
347 for (auto &Action : Actions) {
348 SubCommands.push_back(llvm::make_unique<RefactoringActionSubcommand>(
349 std::move(Action), Action->createActiveActionRules(),
350 opts::CommonRefactorOptions));
351 }
352 }
353
354 using TUCallbackType = llvm::function_ref<void(ASTContext &)>;
355
356 /// Parses the translation units that were given to the subcommand using
357 /// the 'sources' option and invokes the callback for each parsed
358 /// translation unit.
Alex Lorenz3d712c42017-09-14 13:16:14 +0000359 bool foreachTranslationUnit(const CompilationDatabase &DB,
360 ArrayRef<std::string> Sources,
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000361 TUCallbackType Callback) {
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000362 class ToolASTConsumer : public ASTConsumer {
363 public:
364 TUCallbackType Callback;
365 ToolASTConsumer(TUCallbackType Callback) : Callback(Callback) {}
366
367 void HandleTranslationUnit(ASTContext &Context) override {
368 Callback(Context);
369 }
370 };
371 class ActionWrapper {
372 public:
373 TUCallbackType Callback;
374 ActionWrapper(TUCallbackType Callback) : Callback(Callback) {}
375
376 std::unique_ptr<ASTConsumer> newASTConsumer() {
Haojian Wu21cc1382017-10-10 09:48:38 +0000377 return llvm::make_unique<ToolASTConsumer>(Callback);
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000378 }
379 };
380
Alex Lorenz3d712c42017-09-14 13:16:14 +0000381 ClangTool Tool(DB, Sources);
Haojian Wu21cc1382017-10-10 09:48:38 +0000382 ActionWrapper ToolAction(Callback);
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000383 std::unique_ptr<tooling::FrontendActionFactory> Factory =
384 tooling::newFrontendActionFactory(&ToolAction);
385 return Tool.run(Factory.get());
386 }
387
388 /// Logs an individual refactoring action invocation to STDOUT.
389 void logInvocation(RefactoringActionSubcommand &Subcommand,
390 const RefactoringRuleContext &Context) {
391 if (!opts::Verbose)
392 return;
393 llvm::outs() << "invoking action '" << Subcommand.getName() << "':\n";
394 if (Context.getSelectionRange().isValid()) {
395 SourceRange R = Context.getSelectionRange();
396 llvm::outs() << " -selection=";
397 R.getBegin().print(llvm::outs(), Context.getSources());
398 llvm::outs() << " -> ";
399 R.getEnd().print(llvm::outs(), Context.getSources());
400 llvm::outs() << "\n";
401 }
402 }
403
Alex Lorenze1b7b952017-10-16 17:31:16 +0000404 bool applySourceChanges(const AtomicChanges &Replacements) {
405 std::set<std::string> Files;
406 for (const auto &Change : Replacements)
407 Files.insert(Change.getFilePath());
408 // FIXME: Add automatic formatting support as well.
409 tooling::ApplyChangesSpec Spec;
410 // FIXME: We should probably cleanup the result by default as well.
411 Spec.Cleanup = false;
412 for (const auto &File : Files) {
413 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
414 llvm::MemoryBuffer::getFile(File);
415 if (!BufferErr) {
416 llvm::errs() << "error: failed to open " << File << " for rewriting\n";
417 return true;
418 }
419 auto Result = tooling::applyAtomicChanges(File, (*BufferErr)->getBuffer(),
420 Replacements, Spec);
421 if (!Result) {
422 llvm::errs() << toString(Result.takeError());
423 return true;
424 }
425
426 std::error_code EC;
427 llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::F_Text);
428 if (EC) {
429 llvm::errs() << EC.message() << "\n";
430 return true;
431 }
432 OS << *Result;
433 }
434 return false;
435 }
436
Alex Lorenz3d712c42017-09-14 13:16:14 +0000437 bool invokeAction(RefactoringActionSubcommand &Subcommand,
438 const CompilationDatabase &DB,
439 ArrayRef<std::string> Sources) {
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000440 // Find a set of matching rules.
441 SmallVector<RefactoringActionRule *, 4> MatchingRules;
442 llvm::StringSet<> MissingOptions;
443
444 bool HasSelection = false;
445 for (const auto &Rule : Subcommand.getActionRules()) {
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000446 bool SelectionMatches = true;
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000447 if (Rule->hasSelectionRequirement()) {
448 HasSelection = true;
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000449 if (!Subcommand.getSelection()) {
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000450 MissingOptions.insert("selection");
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000451 SelectionMatches = false;
452 }
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000453 }
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000454 CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
455 Rule->visitRefactoringOptions(Visitor);
456 if (SelectionMatches && Visitor.getMissingRequiredOptions().empty()) {
457 MatchingRules.push_back(Rule.get());
458 continue;
459 }
460 for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
461 MissingOptions.insert(Opt->getName());
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000462 }
463 if (MatchingRules.empty()) {
464 llvm::errs() << "error: '" << Subcommand.getName()
465 << "' can't be invoked with the given arguments:\n";
466 for (const auto &Opt : MissingOptions)
467 llvm::errs() << " missing '-" << Opt.getKey() << "' option\n";
468 return true;
469 }
470
471 bool HasFailed = false;
472 ClangRefactorConsumer Consumer;
Alex Lorenz3d712c42017-09-14 13:16:14 +0000473 if (foreachTranslationUnit(DB, Sources, [&](ASTContext &AST) {
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000474 RefactoringRuleContext Context(AST.getSourceManager());
475 Context.setASTContext(AST);
476
477 auto InvokeRule = [&](RefactoringResultConsumer &Consumer) {
478 logInvocation(Subcommand, Context);
479 for (RefactoringActionRule *Rule : MatchingRules) {
480 if (!Rule->hasSelectionRequirement())
481 continue;
482 Rule->invoke(Consumer, Context);
483 return;
484 }
485 // FIXME (Alex L): If more than one initiation succeeded, then the
486 // rules are ambiguous.
487 llvm_unreachable(
488 "The action must have at least one selection rule");
489 };
490
491 if (HasSelection) {
492 assert(Subcommand.getSelection() && "Missing selection argument?");
493 if (opts::Verbose)
494 Subcommand.getSelection()->print(llvm::outs());
495 auto CustomConsumer =
496 Subcommand.getSelection()->createCustomConsumer();
497 if (Subcommand.getSelection()->forAllRanges(
498 Context.getSources(), [&](SourceRange R) {
499 Context.setSelectionRange(R);
500 InvokeRule(CustomConsumer ? *CustomConsumer : Consumer);
501 }))
502 HasFailed = true;
503 return;
504 }
505 // FIXME (Alex L): Implement non-selection based invocation path.
506 }))
507 return true;
Alex Lorenze1b7b952017-10-16 17:31:16 +0000508 return HasFailed || applySourceChanges(Consumer.getSourceChanges());
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000509 }
510};
511
512} // end anonymous namespace
513
514int main(int argc, const char **argv) {
515 ClangRefactorTool Tool;
516
Alex Lorenz3d712c42017-09-14 13:16:14 +0000517 CommonOptionsParser Options(
Alex Lorenzad38fbf2017-10-13 01:53:13 +0000518 argc, argv, cl::GeneralCategory, cl::ZeroOrMore,
Alex Lorenz3d712c42017-09-14 13:16:14 +0000519 "Clang-based refactoring tool for C, C++ and Objective-C");
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000520
521 // Figure out which action is specified by the user. The user must specify
522 // the action using a command-line subcommand, e.g. the invocation
523 // `clang-refactor local-rename` corresponds to the `LocalRename` refactoring
524 // action. All subcommands must have a unique names. This allows us to figure
525 // out which refactoring action should be invoked by looking at the first
526 // subcommand that's enabled by LLVM's command-line parser.
527 auto It = llvm::find_if(
528 Tool.SubCommands,
529 [](const std::unique_ptr<RefactoringActionSubcommand> &SubCommand) {
530 return !!(*SubCommand);
531 });
532 if (It == Tool.SubCommands.end()) {
533 llvm::errs() << "error: no refactoring action given\n";
534 llvm::errs() << "note: the following actions are supported:\n";
535 for (const auto &Subcommand : Tool.SubCommands)
536 llvm::errs().indent(2) << Subcommand->getName() << "\n";
537 return 1;
538 }
539 RefactoringActionSubcommand &ActionCommand = **It;
540
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000541 if (ActionCommand.parseArguments())
542 return 1;
Alex Lorenz3d712c42017-09-14 13:16:14 +0000543 if (Tool.invokeAction(ActionCommand, Options.getCompilations(),
544 Options.getSourcePathList()))
Alex Lorenzb54ef6a2017-09-14 10:06:52 +0000545 return 1;
546
547 return 0;
548}