https://github.com/desyatok created 
https://github.com/llvm/llvm-project/pull/95867

This is a gitlab mirror (LLVM repo is too large to directly create one)

>From 6ac71484e0974f6f928fcab43e02ced5f184ce3c Mon Sep 17 00:00:00 2001
From: Pavel Desyatnikov <desyatnikov...@gmail.com>
Date: Tue, 18 Jun 2024 02:41:55 +0300
Subject: [PATCH] Implement PrimitivesInit refactoring

---
 .../clang/Basic/DiagnosticRefactoringKinds.td |   6 +
 .../RefactoringActionRuleRequirements.h       |  17 ++
 .../Refactoring/VarInits/PrimitiveVarDecl.h   |  26 +++
 .../Refactoring/VarInits/PrimitivesInit.h     |  40 +++++
 clang/lib/Tooling/Refactoring/CMakeLists.txt  |   3 +
 .../Refactoring/RefactoringActions.cpp        |  18 +++
 .../Refactoring/VarInits/PrimitiveVarDecl.cpp |  55 +++++++
 .../VarInits/PrimitiveVarDeclRequirement.cpp  |  32 ++++
 .../Refactoring/VarInits/PrimitivesInit.cpp   |  65 ++++++++
 clang/tools/clang-refactor/ClangRefactor.cpp  | 149 +++++++++++++++++-
 10 files changed, 405 insertions(+), 6 deletions(-)
 create mode 100644 
clang/include/clang/Tooling/Refactoring/VarInits/PrimitiveVarDecl.h
 create mode 100644 
clang/include/clang/Tooling/Refactoring/VarInits/PrimitivesInit.h
 create mode 100644 clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDecl.cpp
 create mode 100644 
clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDeclRequirement.cpp
 create mode 100644 clang/lib/Tooling/Refactoring/VarInits/PrimitivesInit.cpp

diff --git a/clang/include/clang/Basic/DiagnosticRefactoringKinds.td 
b/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
index 5446b32efbdd4..39366bd1492bb 100644
--- a/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
+++ b/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
@@ -28,6 +28,12 @@ def err_refactor_extract_simple_expression : Error<"the 
selected expression "
 def err_refactor_extract_prohibited_expression : Error<"the selected "
   "expression can't be extracted">;
 
+def err_refactor_no_vardecl : Error<"refactoring action can't be initiated "
+  "without a vardecl">;
+def err_refactor_initialized_variable : Error<"the provided vardecl is already 
initialized">;
+def err_refactor_global_variable_init : Error<"no need to initialize global 
variable">;
+def err_refactor_non_primitive_variable : Error<"refactoring action can't be 
initiated "
+  "with non-primitive variable">;
 }
 
 } // end of Refactoring diagnostics
diff --git 
a/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h 
b/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
index 1a318da3acca1..bd410d43abd12 100644
--- 
a/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
+++ 
b/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULEREQUIREMENTS_H
 
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
 #include "clang/Tooling/Refactoring/ASTSelection.h"
 #include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
 #include "clang/Tooling/Refactoring/RefactoringOption.h"
@@ -77,6 +78,17 @@ class CodeRangeASTSelectionRequirement : public 
ASTSelectionRequirement {
   evaluate(RefactoringRuleContext &Context) const;
 };
 
+/// A base class for any requirement that expects source code position
+/// (or the refactoring tool with the -location option).
+class SourceLocationRequirement : public RefactoringActionRuleRequirement {
+public:
+  Expected<SourceLocation> evaluate(RefactoringRuleContext &Context) const {
+    if (Context.getLocation().isValid())
+      return Context.getLocation();
+    return Context.createDiagnosticError(diag::err_refactor_no_location);
+  }
+};
+
 /// A base class for any requirement that requires some refactoring options.
 class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement {
 public:
@@ -116,6 +128,11 @@ class OptionRequirement : public 
RefactoringOptionsRequirement {
   std::shared_ptr<RefactoringOption> Opt;
 };
 
+class PrimitiveVarDeclRequirement : public SourceLocationRequirement {
+public:
+  Expected<VarDecl *> evaluate(RefactoringRuleContext &Context) const;
+};
+
 } // end namespace tooling
 } // end namespace clang
 
diff --git 
a/clang/include/clang/Tooling/Refactoring/VarInits/PrimitiveVarDecl.h 
b/clang/include/clang/Tooling/Refactoring/VarInits/PrimitiveVarDecl.h
new file mode 100644
index 0000000000000..dd9ec755d30c7
--- /dev/null
+++ b/clang/include/clang/Tooling/Refactoring/VarInits/PrimitiveVarDecl.h
@@ -0,0 +1,26 @@
+//===--- PrimitiveVarDecl.h - Clang refactoring library 
----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTORING_VARINITS_PRIMITIVEVARDECL_H
+#define LLVM_CLANG_TOOLING_REFACTORING_VARINITS_PRIMITIVEVARDECL_H
+
+
+namespace clang {
+namespace tooling {
+/// \returns a ptr to concrete DeclRefExpr (it is basically a pointer to
+/// VarDecl) if given SourceLocation is in between
+/// a DeclRefExpr start location and end location
+/// and nullptr otherwise
+DeclRefExpr *getDeclRefExprFromSourceLocation(ASTContext &AST,
+                                              SourceLocation Location);
+
+} // namespace tooling
+} // namespace clang
+
+
+#endif // LLVM_CLANG_TOOLING_REFACTORING_VARINITS_PRIMITIVEVARDECL_H
diff --git a/clang/include/clang/Tooling/Refactoring/VarInits/PrimitivesInit.h 
b/clang/include/clang/Tooling/Refactoring/VarInits/PrimitivesInit.h
new file mode 100644
index 0000000000000..744422b396459
--- /dev/null
+++ b/clang/include/clang/Tooling/Refactoring/VarInits/PrimitivesInit.h
@@ -0,0 +1,40 @@
+//===--- PrimitivesInit.h - Clang refactoring library 
----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTORING_VARINITS_PRIMITIVES_INIT_H
+#define LLVM_CLANG_TOOLING_REFACTORING_VARINITS_PRIMITIVES_INIT_H
+
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+
+namespace clang {
+namespace tooling {
+
+/// \c PrimitivesInit performs the initialization of
+/// a selected primitive variable with a default value
+class PrimitivesInit final : public SourceChangeRefactoringRule {
+public:
+  /// \param Variable        declaration-only VarDecl
+  static Expected<PrimitivesInit>
+  initiate(RefactoringRuleContext &Context, VarDecl *Variable);
+
+  static const RefactoringDescriptor &describe();
+
+private:
+  PrimitivesInit(VarDecl *Variable)
+      : Variable(std::move(Variable)) {}
+
+  Expected<AtomicChanges>
+  createSourceReplacements(RefactoringRuleContext &Context) override;
+
+  VarDecl *Variable;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTORING_VARINITS_PRIMITIVES_INIT_H
diff --git a/clang/lib/Tooling/Refactoring/CMakeLists.txt 
b/clang/lib/Tooling/Refactoring/CMakeLists.txt
index d3077be8810aa..63b9dd700ba35 100644
--- a/clang/lib/Tooling/Refactoring/CMakeLists.txt
+++ b/clang/lib/Tooling/Refactoring/CMakeLists.txt
@@ -13,6 +13,9 @@ add_clang_library(clangToolingRefactoring
   Rename/USRFinder.cpp
   Rename/USRFindingAction.cpp
   Rename/USRLocFinder.cpp
+  VarInits/PrimitivesInit.cpp
+  VarInits/PrimitiveVarDeclRequirement.cpp
+  VarInits/PrimitiveVarDecl.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/Tooling/Refactoring/RefactoringActions.cpp 
b/clang/lib/Tooling/Refactoring/RefactoringActions.cpp
index bf98941f568b3..f68b4daf346ff 100644
--- a/clang/lib/Tooling/Refactoring/RefactoringActions.cpp
+++ b/clang/lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -10,6 +10,7 @@
 #include "clang/Tooling/Refactoring/RefactoringAction.h"
 #include "clang/Tooling/Refactoring/RefactoringOptions.h"
 #include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/Tooling/Refactoring/VarInits/PrimitivesInit.h"
 
 namespace clang {
 namespace tooling {
@@ -93,6 +94,22 @@ class LocalRename final : public RefactoringAction {
   }
 };
 
+class PrimitivesInitAction : public RefactoringAction {
+public:
+  StringRef getCommand() const override { return "init-primitives"; }
+
+  StringRef getDescription() const override {
+    return "Initialization of declared-only primitives";
+  }
+
+  RefactoringActionRules createActionRules() const override {
+    RefactoringActionRules Rules;
+    Rules.push_back(createRefactoringActionRule<PrimitivesInit>(
+        PrimitiveVarDeclRequirement()));
+    return Rules;
+  }
+};
+
 } // end anonymous namespace
 
 std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions() {
@@ -100,6 +117,7 @@ std::vector<std::unique_ptr<RefactoringAction>> 
createRefactoringActions() {
 
   Actions.push_back(std::make_unique<LocalRename>());
   Actions.push_back(std::make_unique<ExtractRefactoring>());
+  Actions.push_back(std::make_unique<PrimitivesInitAction>());
 
   return Actions;
 }
diff --git a/clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDecl.cpp 
b/clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDecl.cpp
new file mode 100644
index 0000000000000..1d416e9bf944e
--- /dev/null
+++ b/clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDecl.cpp
@@ -0,0 +1,55 @@
+//===--- PrimitiveVarDecl.cpp - Clang refactoring library ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
+#include "clang/Tooling/Refactoring/VarInits/PrimitiveVarDecl.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+class VarDeclFinder
+    : public LexicallyOrderedRecursiveASTVisitor<VarDeclFinder> {
+public:
+  VarDeclFinder(SourceLocation Location, FileID TargetFile,
+                const ASTContext &AST)
+      : LexicallyOrderedRecursiveASTVisitor(AST.getSourceManager()),
+        Location(Location), TargetFile(TargetFile), AST(AST) {}
+
+  bool VisitDeclRefExpr(DeclRefExpr *Ref) {
+    const SourceManager &SM = AST.getSourceManager();
+    if (SM.isPointWithin(Location, Ref->getBeginLoc(),
+                         Ref->getEndLoc())) {
+      this->VariableReference = Ref;
+      return false;
+    }
+    return true;
+  }
+
+  DeclRefExpr *getDeclRefExpr() { return VariableReference; }
+
+private:
+  const SourceLocation Location;
+  FileID TargetFile;
+  const ASTContext &AST;
+  DeclRefExpr *VariableReference = nullptr;
+};
+
+} // end anonymous namespace
+
+DeclRefExpr *
+clang::tooling::getDeclRefExprFromSourceLocation(ASTContext &AST,
+                                                 SourceLocation Location) {
+
+  FileID TargetFile = AST.getSourceManager().getFileID(Location);
+
+  VarDeclFinder Visitor(Location, TargetFile, AST);
+  Visitor.TraverseAST(AST);
+  return Visitor.getDeclRefExpr();
+}
diff --git 
a/clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDeclRequirement.cpp 
b/clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDeclRequirement.cpp
new file mode 100644
index 0000000000000..68e31ba147060
--- /dev/null
+++ b/clang/lib/Tooling/Refactoring/VarInits/PrimitiveVarDeclRequirement.cpp
@@ -0,0 +1,32 @@
+//===--- PrimitiveVarDeclRequirement.cpp - Clang refactoring library 
------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
+#include "clang/Tooling/Refactoring/VarInits/PrimitiveVarDecl.h"
+#include <optional>
+
+using namespace clang;
+using namespace tooling;
+
+Expected<VarDecl *>
+PrimitiveVarDeclRequirement::evaluate(RefactoringRuleContext &Context) const {
+  Expected<SourceLocation> Location =
+      SourceLocationRequirement::evaluate(Context);
+  if (!Location)
+    return Location.takeError();
+
+  DeclRefExpr *VariableReference = getDeclRefExprFromSourceLocation(
+      Context.getASTContext(), Location.get());
+
+  if (!VariableReference)
+    return Context.createDiagnosticError(
+        Location.get(), diag::err_refactor_no_vardecl);
+
+  VarDecl *Variable = VariableReference->getDecl()->
+                      getPotentiallyDecomposedVarDecl();
+  return std::move(Variable);
+}
diff --git a/clang/lib/Tooling/Refactoring/VarInits/PrimitivesInit.cpp 
b/clang/lib/Tooling/Refactoring/VarInits/PrimitivesInit.cpp
new file mode 100644
index 0000000000000..76926281794f4
--- /dev/null
+++ b/clang/lib/Tooling/Refactoring/VarInits/PrimitivesInit.cpp
@@ -0,0 +1,65 @@
+//===--- PrimitivesInit.cpp - Clang refactoring library -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/VarInits/PrimitivesInit.h"
+#include "clang/AST/ASTContext.h"
+
+using namespace clang;
+using namespace tooling;
+
+static inline bool VariableHasPrimitiveType(VarDecl *Variable) {
+  return Variable->getType()->isCharType()    ||
+         Variable->getType()->isIntegerType() ||
+         Variable->getType()->isFloatingType();
+}
+
+Expected<PrimitivesInit>
+PrimitivesInit::initiate(RefactoringRuleContext &Context,
+                         VarDecl *Variable) {
+  // Checks whether provided VarDecl is valid
+  if (!Variable->isLocalVarDecl()) {
+    return Context.createDiagnosticError(
+        diag::err_refactor_global_variable_init);
+  }
+
+  if (!VariableHasPrimitiveType(Variable)) {
+    return Context.createDiagnosticError(
+        diag::err_refactor_non_primitive_variable);
+  }
+
+  if (Variable->hasInit()) {
+    return Context.createDiagnosticError(
+        diag::err_refactor_initialized_variable);
+  }
+
+  return PrimitivesInit(std::move(Variable));
+}
+const RefactoringDescriptor &PrimitivesInit::describe() {
+  static const RefactoringDescriptor Descriptor = {
+      "primitives-init",
+      "Primitives Initialization",
+      "Initializes a primitive variable with default value",
+  };
+  return Descriptor;
+}
+
+Expected<AtomicChanges>
+PrimitivesInit::createSourceReplacements(RefactoringRuleContext &Context) {
+  ASTContext &AST = Context.getASTContext();
+  SourceManager &SM = AST.getSourceManager();
+  AtomicChange Replacement(SM, Variable->getLocation());
+  std::string VarName = Variable->getNameAsString();
+  std::string InitWithDefaultValue = (Variable->getType()->isCharType() ?
+                                                                        " = 
\'\\0\'" : " = 0");
+
+  auto Error = Replacement.replace(SM, Variable->getEndLoc(),
+                                   VarName.length(),
+                                   VarName + InitWithDefaultValue);
+  if (Error) return std::move(Error);
+  return AtomicChanges{std::move(Replacement)};
+}
diff --git a/clang/tools/clang-refactor/ClangRefactor.cpp 
b/clang/tools/clang-refactor/ClangRefactor.cpp
index 175a2b8234e9a..c42baba3ef9cd 100644
--- a/clang/tools/clang-refactor/ClangRefactor.cpp
+++ b/clang/tools/clang-refactor/ClangRefactor.cpp
@@ -164,6 +164,83 @@ SourceSelectionArgument::fromString(StringRef Value) {
   return nullptr;
 }
 
+/// Stores the parsed `-location` argument.
+class SourceLocationArgument {
+public:
+  virtual ~SourceLocationArgument() {}
+
+  /// Parse the `-location` argument.
+  ///
+  /// \returns A valid argument when the parse succedeed, null otherwise.
+  static std::unique_ptr<SourceLocationArgument> fromString(StringRef Value);
+
+  /// Prints any additional state associated with the location argument to
+  /// the given output stream.
+  virtual void print(raw_ostream &OS) {}
+
+  /// Returns a replacement refactoring result consumer (if any) that should
+  /// consume the results of a refactoring operation.
+  ///
+  /// The replacement refactoring result consumer is used by \c
+  /// TestSourceLocationArgument to inject a test-specific result handling
+  /// logic into the refactoring operation. The test-specific consumer
+  /// ensures that the individual results in a particular test group are
+  /// identical.
+  virtual std::unique_ptr<ClangRefactorToolConsumerInterface>
+  createCustomConsumer() {
+    return nullptr;
+  }
+
+  /// Runs the given refactoring function for each specified location.
+  ///
+  /// \returns true if an error occurred, false otherwise.
+  virtual bool
+  forAllLocations(const SourceManager &SM,
+                  llvm::function_ref<void(SourceLocation L)> Callback) = 0;
+};
+
+/// Stores the parsed -location=filename:line:column option.
+class SourceLocLocationArgument final : public SourceLocationArgument {
+public:
+  SourceLocLocationArgument(ParsedSourceLocation Location)
+      : Location(std::move(Location)) {}
+
+  bool forAllLocations(const SourceManager &SM,
+                       llvm::function_ref<void(SourceLocation L)> Callback) 
override {
+    auto FE = SM.getFileManager().getFile(Location.FileName);
+    FileID FID = FE ? SM.translateFile(*FE) : FileID();
+    if (!FE || FID.isInvalid()) {
+      llvm::errs() << "error: -location=" << Location.FileName
+                   << ":... : given file is not in the target TU\n";
+      return true;
+    }
+
+    SourceLocation Loc = SM.getMacroArgExpandedLocation(
+        SM.translateLineCol(FID, Location.Line, Location.Column));
+    if (Loc.isInvalid()) {
+      llvm::errs() << "error: -location=" << Location.FileName << ':'
+                   << Location.Line << ':' << Location.Column
+                   << " : invalid source location\n";
+      return true;
+    }
+    Callback(Loc);
+    return false;
+  }
+
+private:
+  ParsedSourceLocation Location;
+};
+
+std::unique_ptr<SourceLocationArgument>
+SourceLocationArgument::fromString(StringRef Value) {
+  std::optional<ParsedSourceLocation> Location = 
ParsedSourceLocation::FromString(Value);
+  if (Location.value().FileName != "")
+    return std::make_unique<SourceLocLocationArgument>(std::move(*Location));
+  llvm::errs() << "error: '-location' option must be specified using "
+                  "<file>:<line>:<column>\n";
+  return nullptr;
+}
+
 /// A container that stores the command-line options used by a single
 /// refactoring option.
 class RefactoringActionCommandLineOptions {
@@ -272,6 +349,18 @@ class RefactoringActionSubcommand : public cl::SubCommand {
         break;
       }
     }
+    // Check if the location option is supported.
+    for (const auto &Rule : this->ActionRules) {
+      if (Rule->hasLocationRequirement()) {
+        Location = std::make_unique<cl::opt<std::string>>(
+            "location",
+            cl::desc(
+                "Location where refactoring should "
+                "be initiated (<file>:<line>:<column>)"),
+            cl::cat(Category), cl::sub(*this));
+        break;
+      }
+    }
     // Create the refactoring options.
     for (const auto &Rule : this->ActionRules) {
       CommandLineRefactoringOptionCreator OptionCreator(Category, *this,
@@ -296,11 +385,28 @@ class RefactoringActionSubcommand : public cl::SubCommand 
{
     return false;
   }
 
+  /// Parses the "-location" command-line argument.
+  ///
+  /// \returns true on error, false otherwise.
+  bool parseLocationArgument() {
+    if (Location) {
+      ParsedLocation = SourceLocationArgument::fromString(*Location);
+      if (!ParsedLocation)
+        return true;
+    }
+    return false;
+  }
+
   SourceSelectionArgument *getSelection() const {
     assert(Selection && "selection not supported!");
     return ParsedSelection.get();
   }
 
+  SourceLocationArgument *getLocation() const {
+    assert(Location && "location not supported!");
+    return ParsedLocation.get();
+  }
+
   const RefactoringActionCommandLineOptions &getOptions() const {
     return Options;
   }
@@ -309,7 +415,9 @@ class RefactoringActionSubcommand : public cl::SubCommand {
   std::unique_ptr<RefactoringAction> Action;
   RefactoringActionRules ActionRules;
   std::unique_ptr<cl::opt<std::string>> Selection;
+  std::unique_ptr<cl::opt<std::string>> Location;
   std::unique_ptr<SourceSelectionArgument> ParsedSelection;
+  std::unique_ptr<SourceLocationArgument> ParsedLocation;
   RefactoringActionCommandLineOptions Options;
 };
 
@@ -399,6 +507,7 @@ class ClangRefactorTool {
     // consumer.
     std::unique_ptr<ClangRefactorToolConsumerInterface> TestConsumer;
     bool HasSelection = MatchingRule->hasSelectionRequirement();
+    bool HasLocation = MatchingRule->hasLocationRequirement();
     if (HasSelection)
       TestConsumer = 
SelectedSubcommand->getSelection()->createCustomConsumer();
     ClangRefactorToolConsumerInterface *ActiveConsumer =
@@ -424,6 +533,20 @@ class ClangRefactorTool {
       ActiveConsumer->endTU();
       return;
     }
+    if (HasLocation) {
+      assert(SelectedSubcommand->getLocation() &&
+             "Missing location argument?");
+      if (opts::Verbose)
+        SelectedSubcommand->getLocation()->print(llvm::outs());
+      if (SelectedSubcommand->getLocation()->forAllLocations(
+              Context.getSources(), [&](SourceLocation L) {
+                Context.setLocation(L);
+                InvokeRule(*ActiveConsumer);
+              }))
+        HasFailed = true;
+      ActiveConsumer->endTU();
+      return;
+    }
     InvokeRule(*ActiveConsumer);
     ActiveConsumer->endTU();
   }
@@ -528,6 +651,12 @@ class ClangRefactorTool {
       R.getEnd().print(llvm::outs(), Context.getSources());
       llvm::outs() << "\n";
     }
+    if (Context.getLocation().isValid()) {
+      SourceLocation L = Context.getLocation();
+      llvm::outs() << "  -location=";
+      L.print(llvm::outs(), Context.getSources());
+      llvm::outs() << "\n";
+    }
   }
 
   llvm::Expected<RefactoringActionRule *>
@@ -539,16 +668,24 @@ class ClangRefactorTool {
       CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
       Rule->visitRefactoringOptions(Visitor);
       if (Visitor.getMissingRequiredOptions().empty()) {
-        if (!Rule->hasSelectionRequirement()) {
-          MatchingRules.push_back(Rule.get());
-        } else {
+        bool HasMissingOptions = false;
+        if (Rule->hasSelectionRequirement()) {
           Subcommand.parseSelectionArgument();
-          if (Subcommand.getSelection()) {
-            MatchingRules.push_back(Rule.get());
-          } else {
+          if (!Subcommand.getSelection()) {
             MissingOptions.insert("selection");
+            HasMissingOptions = true;
           }
         }
+        if (Rule->hasLocationRequirement()) {
+          Subcommand.parseLocationArgument();
+          if (!Subcommand.getLocation()) {
+            MissingOptions.insert("location");
+            HasMissingOptions = true;
+          }
+        }
+        if (!HasMissingOptions) {
+          MatchingRules.push_back(Rule.get());
+        }
       }
       for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
         MissingOptions.insert(Opt->getName());

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to