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