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().getFile(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\n";
164 return nullptr;
165}
166
167/// A container that stores the command-line options used by a single
168/// refactoring option.
169class RefactoringActionCommandLineOptions {
170public:
171 void addStringOption(const RefactoringOption &Option,
172 std::unique_ptr<cl::opt<std::string>> CLOption) {
173 StringOptions[&Option] = std::move(CLOption);
174 }
175
176 const cl::opt<std::string> &
177 getStringOption(const RefactoringOption &Opt) const {
178 auto It = StringOptions.find(Val: &Opt);
179 return *It->second;
180 }
181
182private:
183 llvm::DenseMap<const RefactoringOption *,
184 std::unique_ptr<cl::opt<std::string>>>
185 StringOptions;
186};
187
188/// Passes the command-line option values to the options used by a single
189/// refactoring action rule.
190class CommandLineRefactoringOptionVisitor final
191 : public RefactoringOptionVisitor {
192public:
193 CommandLineRefactoringOptionVisitor(
194 const RefactoringActionCommandLineOptions &Options)
195 : Options(Options) {}
196
197 void visit(const RefactoringOption &Opt,
198 std::optional<std::string> &Value) override {
199 const cl::opt<std::string> &CLOpt = Options.getStringOption(Opt);
200 if (!CLOpt.getValue().empty()) {
201 Value = CLOpt.getValue();
202 return;
203 }
204 Value = std::nullopt;
205 if (Opt.isRequired())
206 MissingRequiredOptions.push_back(Elt: &Opt);
207 }
208
209 ArrayRef<const RefactoringOption *> getMissingRequiredOptions() const {
210 return MissingRequiredOptions;
211 }
212
213private:
214 llvm::SmallVector<const RefactoringOption *, 4> MissingRequiredOptions;
215 const RefactoringActionCommandLineOptions &Options;
216};
217
218/// Creates the refactoring options used by all the rules in a single
219/// refactoring action.
220class CommandLineRefactoringOptionCreator final
221 : public RefactoringOptionVisitor {
222public:
223 CommandLineRefactoringOptionCreator(
224 cl::OptionCategory &Category, cl::SubCommand &Subcommand,
225 RefactoringActionCommandLineOptions &Options)
226 : Category(Category), Subcommand(Subcommand), Options(Options) {}
227
228 void visit(const RefactoringOption &Opt,
229 std::optional<std::string> &) override {
230 if (Visited.insert(Ptr: &Opt).second)
231 Options.addStringOption(Option: Opt, CLOption: create<std::string>(Opt));
232 }
233
234private:
235 template <typename T>
236 std::unique_ptr<cl::opt<T>> create(const RefactoringOption &Opt) {
237 if (!OptionNames.insert(key: Opt.getName()).second)
238 llvm::report_fatal_error(reason: "Multiple identical refactoring options "
239 "specified for one refactoring action");
240 // FIXME: cl::Required can be specified when this option is present
241 // in all rules in an action.
242 return std::make_unique<cl::opt<T>>(
243 Opt.getName(), cl::desc(Opt.getDescription()), cl::Optional,
244 cl::cat(Category), cl::sub(Subcommand));
245 }
246
247 llvm::SmallPtrSet<const RefactoringOption *, 8> Visited;
248 llvm::StringSet<> OptionNames;
249 cl::OptionCategory &Category;
250 cl::SubCommand &Subcommand;
251 RefactoringActionCommandLineOptions &Options;
252};
253
254/// A subcommand that corresponds to individual refactoring action.
255class RefactoringActionSubcommand : public cl::SubCommand {
256public:
257 RefactoringActionSubcommand(std::unique_ptr<RefactoringAction> Action,
258 RefactoringActionRules ActionRules,
259 cl::OptionCategory &Category)
260 : SubCommand(Action->getCommand(), Action->getDescription()),
261 Action(std::move(Action)), ActionRules(std::move(ActionRules)) {
262 // Check if the selection option is supported.
263 for (const auto &Rule : this->ActionRules) {
264 if (Rule->hasSelectionRequirement()) {
265 Selection = std::make_unique<cl::opt<std::string>>(
266 args: "selection",
267 args: cl::desc(
268 "The selected source range in which the refactoring should "
269 "be initiated (<file>:<line>:<column>-<line>:<column> or "
270 "<file>:<line>:<column>)"),
271 args: cl::cat(Category), args: cl::sub(*this));
272 break;
273 }
274 }
275 // Create the refactoring options.
276 for (const auto &Rule : this->ActionRules) {
277 CommandLineRefactoringOptionCreator OptionCreator(Category, *this,
278 Options);
279 Rule->visitRefactoringOptions(Visitor&: OptionCreator);
280 }
281 }
282
283 ~RefactoringActionSubcommand() { unregisterSubCommand(); }
284
285 const RefactoringActionRules &getActionRules() const { return ActionRules; }
286
287 /// Parses the "-selection" command-line argument.
288 ///
289 /// \returns true on error, false otherwise.
290 bool parseSelectionArgument() {
291 if (Selection) {
292 ParsedSelection = SourceSelectionArgument::fromString(Value: *Selection);
293 if (!ParsedSelection)
294 return true;
295 }
296 return false;
297 }
298
299 SourceSelectionArgument *getSelection() const {
300 assert(Selection && "selection not supported!");
301 return ParsedSelection.get();
302 }
303
304 const RefactoringActionCommandLineOptions &getOptions() const {
305 return Options;
306 }
307
308private:
309 std::unique_ptr<RefactoringAction> Action;
310 RefactoringActionRules ActionRules;
311 std::unique_ptr<cl::opt<std::string>> Selection;
312 std::unique_ptr<SourceSelectionArgument> ParsedSelection;
313 RefactoringActionCommandLineOptions Options;
314};
315
316class ClangRefactorConsumer final : public ClangRefactorToolConsumerInterface {
317public:
318 ClangRefactorConsumer(AtomicChanges &Changes) : SourceChanges(&Changes) {}
319
320 void handleError(llvm::Error Err) override {
321 std::optional<PartialDiagnosticAt> Diag = DiagnosticError::take(Err);
322 if (!Diag) {
323 llvm::errs() << llvm::toString(E: std::move(Err)) << "\n";
324 return;
325 }
326 llvm::cantFail(Err: std::move(Err)); // This is a success.
327 DiagnosticBuilder DB(
328 getDiags().Report(Loc: Diag->first, DiagID: Diag->second.getDiagID()));
329 Diag->second.Emit(DB);
330 }
331
332 void handle(AtomicChanges Changes) override {
333 SourceChanges->insert(position: SourceChanges->begin(), first: Changes.begin(),
334 last: Changes.end());
335 }
336
337 void handle(SymbolOccurrences Occurrences) override {
338 llvm_unreachable("symbol occurrence results are not handled yet");
339 }
340
341private:
342 AtomicChanges *SourceChanges;
343};
344
345class ClangRefactorTool {
346public:
347 ClangRefactorTool()
348 : SelectedSubcommand(nullptr), MatchingRule(nullptr),
349 Consumer(new ClangRefactorConsumer(Changes)), HasFailed(false) {
350 std::vector<std::unique_ptr<RefactoringAction>> Actions =
351 createRefactoringActions();
352
353 // Actions must have unique command names so that we can map them to one
354 // subcommand.
355 llvm::StringSet<> CommandNames;
356 for (const auto &Action : Actions) {
357 if (!CommandNames.insert(key: Action->getCommand()).second) {
358 llvm::errs() << "duplicate refactoring action command '"
359 << Action->getCommand() << "'!";
360 exit(status: 1);
361 }
362 }
363
364 // Create subcommands and command-line options.
365 for (auto &Action : Actions) {
366 SubCommands.push_back(x: std::make_unique<RefactoringActionSubcommand>(
367 args: std::move(Action), args: Action->createActiveActionRules(),
368 args&: opts::CommonRefactorOptions));
369 }
370 }
371
372 // Initializes the selected subcommand and refactoring rule based on the
373 // command line options.
374 llvm::Error Init() {
375 auto Subcommand = getSelectedSubcommand();
376 if (!Subcommand)
377 return Subcommand.takeError();
378 auto Rule = getMatchingRule(Subcommand&: **Subcommand);
379 if (!Rule)
380 return Rule.takeError();
381
382 SelectedSubcommand = *Subcommand;
383 MatchingRule = *Rule;
384
385 return llvm::Error::success();
386 }
387
388 bool hasFailed() const { return HasFailed; }
389
390 using TUCallbackType = std::function<void(ASTContext &)>;
391
392 // Callback of an AST action. This invokes the matching rule on the given AST.
393 void callback(ASTContext &AST) {
394 assert(SelectedSubcommand && MatchingRule && Consumer);
395 RefactoringRuleContext Context(AST.getSourceManager());
396 Context.setASTContext(AST);
397
398 // If the selection option is test specific, we use a test-specific
399 // consumer.
400 std::unique_ptr<ClangRefactorToolConsumerInterface> TestConsumer;
401 bool HasSelection = MatchingRule->hasSelectionRequirement();
402 if (HasSelection)
403 TestConsumer = SelectedSubcommand->getSelection()->createCustomConsumer();
404 ClangRefactorToolConsumerInterface *ActiveConsumer =
405 TestConsumer ? TestConsumer.get() : Consumer.get();
406 ActiveConsumer->beginTU(Context&: AST);
407
408 auto InvokeRule = [&](RefactoringResultConsumer &Consumer) {
409 if (opts::Verbose)
410 logInvocation(Subcommand&: *SelectedSubcommand, Context);
411 MatchingRule->invoke(Consumer&: *ActiveConsumer, Context);
412 };
413 if (HasSelection) {
414 assert(SelectedSubcommand->getSelection() &&
415 "Missing selection argument?");
416 if (opts::Verbose)
417 SelectedSubcommand->getSelection()->print(OS&: llvm::outs());
418 if (SelectedSubcommand->getSelection()->forAllRanges(
419 SM: Context.getSources(), Callback: [&](SourceRange R) {
420 Context.setSelectionRange(R);
421 InvokeRule(*ActiveConsumer);
422 }))
423 HasFailed = true;
424 ActiveConsumer->endTU();
425 return;
426 }
427 InvokeRule(*ActiveConsumer);
428 ActiveConsumer->endTU();
429 }
430
431 llvm::Expected<std::unique_ptr<FrontendActionFactory>>
432 getFrontendActionFactory() {
433 class ToolASTConsumer : public ASTConsumer {
434 public:
435 TUCallbackType Callback;
436 ToolASTConsumer(TUCallbackType Callback)
437 : Callback(std::move(Callback)) {}
438
439 void HandleTranslationUnit(ASTContext &Context) override {
440 Callback(Context);
441 }
442 };
443 class ToolASTAction : public ASTFrontendAction {
444 public:
445 explicit ToolASTAction(TUCallbackType Callback)
446 : Callback(std::move(Callback)) {}
447
448 protected:
449 std::unique_ptr<clang::ASTConsumer>
450 CreateASTConsumer(clang::CompilerInstance &compiler,
451 StringRef /* dummy */) override {
452 std::unique_ptr<clang::ASTConsumer> Consumer{
453 new ToolASTConsumer(Callback)};
454 return Consumer;
455 }
456
457 private:
458 TUCallbackType Callback;
459 };
460
461 class ToolActionFactory : public FrontendActionFactory {
462 public:
463 ToolActionFactory(TUCallbackType Callback)
464 : Callback(std::move(Callback)) {}
465
466 std::unique_ptr<FrontendAction> create() override {
467 return std::make_unique<ToolASTAction>(args&: Callback);
468 }
469
470 private:
471 TUCallbackType Callback;
472 };
473
474 return std::make_unique<ToolActionFactory>(
475 args: [this](ASTContext &AST) { return callback(AST); });
476 }
477
478 // FIXME(ioeric): this seems to only works for changes in a single file at
479 // this point.
480 bool applySourceChanges() {
481 std::set<std::string> Files;
482 for (const auto &Change : Changes)
483 Files.insert(x: Change.getFilePath());
484 // FIXME: Add automatic formatting support as well.
485 tooling::ApplyChangesSpec Spec;
486 // FIXME: We should probably cleanup the result by default as well.
487 Spec.Cleanup = false;
488 for (const auto &File : Files) {
489 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
490 llvm::MemoryBuffer::getFile(Filename: File);
491 if (!BufferErr) {
492 llvm::errs() << "error: failed to open " << File << " for rewriting\n";
493 return true;
494 }
495 auto Result = tooling::applyAtomicChanges(FilePath: File, Code: (*BufferErr)->getBuffer(),
496 Changes, Spec);
497 if (!Result) {
498 llvm::errs() << toString(E: Result.takeError());
499 return true;
500 }
501
502 if (opts::Inplace) {
503 std::error_code EC;
504 llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::OF_TextWithCRLF);
505 if (EC) {
506 llvm::errs() << EC.message() << "\n";
507 return true;
508 }
509 OS << *Result;
510 continue;
511 }
512
513 llvm::outs() << *Result;
514 }
515 return false;
516 }
517
518private:
519 /// Logs an individual refactoring action invocation to STDOUT.
520 void logInvocation(RefactoringActionSubcommand &Subcommand,
521 const RefactoringRuleContext &Context) {
522 llvm::outs() << "invoking action '" << Subcommand.getName() << "':\n";
523 if (Context.getSelectionRange().isValid()) {
524 SourceRange R = Context.getSelectionRange();
525 llvm::outs() << " -selection=";
526 R.getBegin().print(OS&: llvm::outs(), SM: Context.getSources());
527 llvm::outs() << " -> ";
528 R.getEnd().print(OS&: llvm::outs(), SM: Context.getSources());
529 llvm::outs() << "\n";
530 }
531 }
532
533 llvm::Expected<RefactoringActionRule *>
534 getMatchingRule(RefactoringActionSubcommand &Subcommand) {
535 SmallVector<RefactoringActionRule *, 4> MatchingRules;
536 llvm::StringSet<> MissingOptions;
537
538 for (const auto &Rule : Subcommand.getActionRules()) {
539 CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
540 Rule->visitRefactoringOptions(Visitor);
541 if (Visitor.getMissingRequiredOptions().empty()) {
542 if (!Rule->hasSelectionRequirement()) {
543 MatchingRules.push_back(Elt: Rule.get());
544 } else {
545 Subcommand.parseSelectionArgument();
546 if (Subcommand.getSelection()) {
547 MatchingRules.push_back(Elt: Rule.get());
548 } else {
549 MissingOptions.insert(key: "selection");
550 }
551 }
552 }
553 for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
554 MissingOptions.insert(key: Opt->getName());
555 }
556 if (MatchingRules.empty()) {
557 std::string Error;
558 llvm::raw_string_ostream OS(Error);
559 OS << "ERROR: '" << Subcommand.getName()
560 << "' can't be invoked with the given arguments:\n";
561 for (const auto &Opt : MissingOptions)
562 OS << " missing '-" << Opt.getKey() << "' option\n";
563 OS.flush();
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 OS.flush();
595 return llvm::make_error<llvm::StringError>(
596 Args&: Error, Args: llvm::inconvertibleErrorCode());
597 }
598 RefactoringActionSubcommand *Subcommand = &(**It);
599 return Subcommand;
600 }
601
602 std::vector<std::unique_ptr<RefactoringActionSubcommand>> SubCommands;
603 RefactoringActionSubcommand *SelectedSubcommand;
604 RefactoringActionRule *MatchingRule;
605 std::unique_ptr<ClangRefactorToolConsumerInterface> Consumer;
606 AtomicChanges Changes;
607 bool HasFailed;
608};
609
610} // end anonymous namespace
611
612int main(int argc, const char **argv) {
613 llvm::sys::PrintStackTraceOnErrorSignal(Argv0: argv[0]);
614
615 ClangRefactorTool RefactorTool;
616
617 auto ExpectedParser = CommonOptionsParser::create(
618 argc, argv, Category&: cl::getGeneralCategory(), OccurrencesFlag: cl::ZeroOrMore,
619 Overview: "Clang-based refactoring tool for C, C++ and Objective-C");
620 if (!ExpectedParser) {
621 llvm::errs() << ExpectedParser.takeError();
622 return 1;
623 }
624 CommonOptionsParser &Options = ExpectedParser.get();
625
626 if (auto Err = RefactorTool.Init()) {
627 llvm::errs() << llvm::toString(E: std::move(Err)) << "\n";
628 return 1;
629 }
630
631 auto ActionFactory = RefactorTool.getFrontendActionFactory();
632 if (!ActionFactory) {
633 llvm::errs() << llvm::toString(E: ActionFactory.takeError()) << "\n";
634 return 1;
635 }
636 ClangTool Tool(Options.getCompilations(), Options.getSourcePathList());
637 bool Failed = false;
638 if (Tool.run(Action: ActionFactory->get()) != 0) {
639 llvm::errs() << "Failed to run refactoring action on files\n";
640 // It is possible that TUs are broken while changes are generated correctly,
641 // so we still try applying changes.
642 Failed = true;
643 }
644 return RefactorTool.applySourceChanges() || Failed ||
645 RefactorTool.hasFailed();
646}
647

source code of clang/tools/clang-refactor/ClangRefactor.cpp