ClangRefactor.cpp 22 KB

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