[clang] Clang-Refactor (PR #94855)

Сергеев Игнатий via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 8 06:10:52 PDT 2024


https://github.com/IgnatSergeev created https://github.com/llvm/llvm-project/pull/94855

None

>From d206a7e8fd690ce9d97a5f0278d0347d59d0c18d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=98=D0=B3=D0=BD=D0=B0=D1=82=20=D0=A1=D0=B5=D1=80=D0=B3?=
 =?UTF-8?q?=D0=B5=D0=B5=D0=B2?= <ignat.sergeev at softcom.su>
Date: Mon, 27 May 2024 19:43:11 +0000
Subject: [PATCH 1/3] Merge branch '1-source-location-requirement' into
 'dev-rk'

Added source location requirement

See merge request llvm/llvm-project!6

(cherry picked from commit ff149ddaae4fc2a89879b16fc754ba5094adfc8b)

083b626e Added source location requirement
424b878c Added source location requirement
25c29ca9 Added source location argument
6e7a40da Removed test argument
e5bb6ef4 Added parse
41b4b3b2 Removed test support argument
8e40aa48 Added hasLoctionRequirement
75067db6 Fixed multiple definitions
---
 .../clang/Basic/DiagnosticRefactoringKinds.td        |  2 ++
 .../Tooling/Refactoring/RefactoringActionRule.h      |  4 ++++
 .../Refactoring/RefactoringActionRuleRequirements.h  | 11 +++++++++++
 .../Refactoring/RefactoringActionRulesInternal.h     |  5 +++++
 .../Tooling/Refactoring/RefactoringRuleContext.h     | 12 ++++++++++++
 5 files changed, 34 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticRefactoringKinds.td b/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
index 5446b32efbdd4..da35eae93df9a 100644
--- a/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
+++ b/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
@@ -28,6 +28,8 @@ 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_location : Error<"refactoring action can't be initiated "
+  "without a location">;
 }
 
 } // end of Refactoring diagnostics
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h b/clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h
index c6a6c4f6093a3..374f19d6d8233 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h
@@ -56,6 +56,10 @@ class RefactoringActionRule : public RefactoringActionRuleBase {
   /// to be fulfilled before refactoring can be performed.
   virtual bool hasSelectionRequirement() = 0;
 
+  /// Returns true when the rule has a source location requirement that has
+  /// to be fulfilled before refactoring can be performed.
+  virtual bool hasLocationRequirement() = 0;
+
   /// Traverses each refactoring option used by the rule and invokes the
   /// \c visit callback in the consumer for each option.
   ///
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
index 1a318da3acca1..fe7f96064b81c 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,16 @@ 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:
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
index 33194c401ea14..52afb012f4874 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
@@ -139,6 +139,11 @@ createRefactoringActionRule(const RequirementTypes &... Requirements) {
                                  RequirementTypes...>::value;
     }
 
+    bool hasLocationRequirement() override {
+      return internal::HasBaseOf<SourceLocationRequirement,
+                                 RequirementTypes...>::value;
+    }
+
     void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override {
       internal::visitRefactoringOptions(
           Visitor, Requirements,
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h b/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
index 7d97f811f024e..85bba662afcd2 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
@@ -30,6 +30,9 @@ namespace tooling {
 ///
 ///   - SelectionRange: an optional source selection ranges that can be used
 ///     to represent a selection in an editor.
+///
+///   - Location: an optional source location that can be used
+///     to represent a cursor in an editor.
 class RefactoringRuleContext {
 public:
   RefactoringRuleContext(const SourceManager &SM) : SM(SM) {}
@@ -40,8 +43,14 @@ class RefactoringRuleContext {
   /// refactoring engine. Can be invalid.
   SourceRange getSelectionRange() const { return SelectionRange; }
 
+  /// Returns the current source location as set by the
+  /// refactoring engine. Can be invalid.
+  SourceLocation getLocation() const { return Location; }
+
   void setSelectionRange(SourceRange R) { SelectionRange = R; }
 
+  void setLocation(SourceLocation L) { Location = L; }
+
   bool hasASTContext() const { return AST; }
 
   ASTContext &getASTContext() const {
@@ -73,6 +82,9 @@ class RefactoringRuleContext {
   /// An optional source selection range that's commonly used to represent
   /// a selection in an editor.
   SourceRange SelectionRange;
+  /// An optional source location that's commonly used to represent
+  /// a cursor in an editor.
+  SourceLocation Location;
   /// An optional AST for the translation unit on which a refactoring action
   /// might operate on.
   ASTContext *AST = nullptr;

>From de0b81def79cdadbe0126827cc46f114e73fa732 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=98=D0=B3=D0=BD=D0=B0=D1=82=20=D0=A1=D0=B5=D1=80=D0=B3?=
 =?UTF-8?q?=D0=B5=D0=B5=D0=B2?= <ignat.sergeev at softcom.su>
Date: Mon, 27 May 2024 20:26:52 +0000
Subject: [PATCH 2/3] Merge branch '1-source-location-argument' into 'dev-rk'

Added source location argument

See merge request llvm/llvm-project!7

(cherry picked from commit 45adb8a1bb2b9b7dbf6f6a5657f5fc84ed2c0613)

ab5ae37c Added source location argument
78824379 Added full argument support
58eb8a70 Added full argument support
ee61e58e Merge branch 'dev-rk' into 1-source-location-argument
841e2896 Fixed
bab91c9a Fixed
---
 clang/tools/clang-refactor/ClangRefactor.cpp | 149 ++++++++++++++++++-
 1 file changed, 143 insertions(+), 6 deletions(-)

diff --git a/clang/tools/clang-refactor/ClangRefactor.cpp b/clang/tools/clang-refactor/ClangRefactor.cpp
index 175a2b8234e9a..d936e56b77b19 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)
+    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());

>From 7220c45b1a66b4bf49b6d9206c53de2598ead6b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=98=D0=B3=D0=BD=D0=B0=D1=82=20=D0=A1=D0=B5=D1=80=D0=B3?=
 =?UTF-8?q?=D0=B5=D0=B5=D0=B2?= <ignat.sergeev at softcom.su>
Date: Fri, 7 Jun 2024 23:48:32 +0000
Subject: [PATCH 3/3] Added delete statement refactoring rule

---
 .../clang/Basic/DiagnosticRefactoringKinds.td |  2 +
 .../clang/Tooling/Refactoring/ASTStatement.h  | 30 +++++++++
 .../Refactoring/Delete/DeleteStatementRule.h  | 41 ++++++++++++
 .../RefactoringActionRuleRequirements.h       |  9 +++
 .../lib/Tooling/Refactoring/ASTStatement.cpp  | 58 +++++++++++++++++
 .../Refactoring/ASTStatementRequirements.cpp  | 28 +++++++++
 clang/lib/Tooling/Refactoring/CMakeLists.txt  |  3 +
 .../Delete/DeleteStatementRule.cpp            | 62 +++++++++++++++++++
 8 files changed, 233 insertions(+)
 create mode 100644 clang/include/clang/Tooling/Refactoring/ASTStatement.h
 create mode 100644 clang/include/clang/Tooling/Refactoring/Delete/DeleteStatementRule.h
 create mode 100644 clang/lib/Tooling/Refactoring/ASTStatement.cpp
 create mode 100644 clang/lib/Tooling/Refactoring/ASTStatementRequirements.cpp
 create mode 100644 clang/lib/Tooling/Refactoring/Delete/DeleteStatementRule.cpp

diff --git a/clang/include/clang/Basic/DiagnosticRefactoringKinds.td b/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
index da35eae93df9a..6f3e2f1724d06 100644
--- a/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
+++ b/clang/include/clang/Basic/DiagnosticRefactoringKinds.td
@@ -30,6 +30,8 @@ def err_refactor_extract_prohibited_expression : Error<"the selected "
 
 def err_refactor_no_location : Error<"refactoring action can't be initiated "
   "without a location">;
+def err_refactor_location_no_statement : Error<"the provided location is not "
+  "surrouded by an AST statement">;
 }
 
 } // end of Refactoring diagnostics
diff --git a/clang/include/clang/Tooling/Refactoring/ASTStatement.h b/clang/include/clang/Tooling/Refactoring/ASTStatement.h
new file mode 100644
index 0000000000000..168c68ecd2d36
--- /dev/null
+++ b/clang/include/clang/Tooling/Refactoring/ASTStatement.h
@@ -0,0 +1,30 @@
+//===--- ASTStatement.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_ASTSTATEMENT_H
+#define LLVM_CLANG_TOOLING_REFACTORING_ASTSTATEMENT_H
+
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+class ASTContext;
+
+namespace tooling {
+
+/// Traverses the given ASTContext and finds closest outer statement.
+///
+/// \returns nullptr if location is not surrounded by any statement, or a AST
+/// statement otherwise.
+Stmt *findOuterStmt(const ASTContext &Context,
+                    SourceLocation Location);
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTORING_ASTSTATEMENT_H
diff --git a/clang/include/clang/Tooling/Refactoring/Delete/DeleteStatementRule.h b/clang/include/clang/Tooling/Refactoring/Delete/DeleteStatementRule.h
new file mode 100644
index 0000000000000..51babee0716c2
--- /dev/null
+++ b/clang/include/clang/Tooling/Refactoring/Delete/DeleteStatementRule.h
@@ -0,0 +1,41 @@
+//===--- DeleteStatementRule.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_DELETE_DELETESTATEMENTRULE_H
+#define LLVM_CLANG_TOOLING_REFACTORING_DELETE_DELETESTATEMENTRULE_H
+
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+
+namespace clang {
+namespace tooling {
+
+/// A "Delete Statement" refactoring rule deletes code around given statement
+class DeleteStatementRule final : public SourceChangeRefactoringRule {
+public:
+  /// Initiates the delete statement refactoring operation.
+  ///
+  /// \param Statement    Statement to delete.
+  static Expected<DeleteStatementRule>
+  initiate(RefactoringRuleContext &Context, Stmt *Stmt);
+
+  static const RefactoringDescriptor &describe();
+
+private:
+  DeleteStatementRule(Stmt *Stmt)
+      : Statement(std::move(Stmt)) {}
+
+  Expected<AtomicChanges>
+  createSourceReplacements(RefactoringRuleContext &Context) override;
+
+  Stmt *Statement;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTORING_DELETE_DELETESTATEMENTRULE_H
diff --git a/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
index fe7f96064b81c..2550dd07ba2c9 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
@@ -88,6 +88,15 @@ class SourceLocationRequirement : public RefactoringActionRuleRequirement {
   }
 };
 
+/// An AST statement requirement is satisfied when location is surrounded by statement.
+///
+/// The requirement will be evaluated only once during the initiation and
+/// search of matching refactoring action rules.
+class ASTStatementRequirement : public SourceLocationRequirement {
+public:
+  Expected<Stmt *> evaluate(RefactoringRuleContext &Context) const;
+};
+
 /// A base class for any requirement that requires some refactoring options.
 class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement {
 public:
diff --git a/clang/lib/Tooling/Refactoring/ASTStatement.cpp b/clang/lib/Tooling/Refactoring/ASTStatement.cpp
new file mode 100644
index 0000000000000..62c635fe75681
--- /dev/null
+++ b/clang/lib/Tooling/Refactoring/ASTStatement.cpp
@@ -0,0 +1,58 @@
+//===--- ASTStatement.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/ASTStatement.h"
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+class ASTStatementFinder
+    : public LexicallyOrderedRecursiveASTVisitor<ASTStatementFinder> {
+public:
+  ASTStatementFinder(SourceLocation Location, FileID TargetFile,
+                     const ASTContext &Context)
+      : LexicallyOrderedRecursiveASTVisitor(Context.getSourceManager()),
+        Location(std::move(Location)),
+        TargetFile(TargetFile), Context(Context) {}
+
+  bool TraverseStmt(Stmt *Statement) {
+    if (!Statement)
+        return true;
+    const SourceManager &SM = Context.getSourceManager();
+    if (SM.isPointWithin(Location, Statement->getBeginLoc(), Statement->getEndLoc())) {
+      this->Statement = Statement;
+    }
+    LexicallyOrderedRecursiveASTVisitor::TraverseStmt(Statement);
+    return true;
+  }
+
+  Stmt *getOuterStatement() {
+    return Statement;
+  }
+private:
+  const SourceLocation Location;
+  FileID TargetFile;
+  const ASTContext &Context;
+  Stmt *Statement = nullptr;
+};
+
+} // end anonymous namespace
+
+Stmt *
+clang::tooling::findOuterStmt(const ASTContext &Context, SourceLocation Location) {
+  assert(Location.isValid() && Location.isFileID() && "Expected a file location");
+
+  FileID TargetFile = Context.getSourceManager().getFileID(Location);
+
+  ASTStatementFinder Visitor(Location, TargetFile, Context);
+  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+  return Visitor.getOuterStatement();
+}
diff --git a/clang/lib/Tooling/Refactoring/ASTStatementRequirements.cpp b/clang/lib/Tooling/Refactoring/ASTStatementRequirements.cpp
new file mode 100644
index 0000000000000..5e1ba7c240a11
--- /dev/null
+++ b/clang/lib/Tooling/Refactoring/ASTStatementRequirements.cpp
@@ -0,0 +1,28 @@
+//===--- ASTStatementRequirements.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/ASTStatement.h"
+
+using namespace clang;
+using namespace tooling;
+
+Expected<Stmt *>
+ASTStatementRequirement::evaluate(RefactoringRuleContext &Context) const {
+  Expected<SourceLocation> Location =
+      SourceLocationRequirement::evaluate(Context);
+  if (!Location)
+    return Location.takeError();
+
+  Stmt *Statement =
+      findOuterStmt(Context.getASTContext(), *Location);
+  if (Statement == nullptr)
+    return Context.createDiagnosticError(
+        *Location, diag::err_refactor_location_no_statement);
+  return std::move(Statement);
+}
diff --git a/clang/lib/Tooling/Refactoring/CMakeLists.txt b/clang/lib/Tooling/Refactoring/CMakeLists.txt
index d3077be8810aa..2a6bd1a7d83c3 100644
--- a/clang/lib/Tooling/Refactoring/CMakeLists.txt
+++ b/clang/lib/Tooling/Refactoring/CMakeLists.txt
@@ -3,6 +3,8 @@ set(LLVM_LINK_COMPONENTS Support)
 add_clang_library(clangToolingRefactoring
   ASTSelection.cpp
   ASTSelectionRequirements.cpp
+  ASTStatement.cpp
+  ASTStatementRequirements.cpp
   AtomicChange.cpp
   Extract/Extract.cpp
   Extract/SourceExtraction.cpp
@@ -13,6 +15,7 @@ add_clang_library(clangToolingRefactoring
   Rename/USRFinder.cpp
   Rename/USRFindingAction.cpp
   Rename/USRLocFinder.cpp
+  Delete/DeleteStatementRule.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/Tooling/Refactoring/Delete/DeleteStatementRule.cpp b/clang/lib/Tooling/Refactoring/Delete/DeleteStatementRule.cpp
new file mode 100644
index 0000000000000..bacade7e9b8a7
--- /dev/null
+++ b/clang/lib/Tooling/Refactoring/Delete/DeleteStatementRule.cpp
@@ -0,0 +1,62 @@
+//===--- DeleteStatementRule.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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implements the "delete-statement" refactoring rule that can delete stmts
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/ASTStatement.h"
+#include "clang/Tooling/Refactoring/Delete/DeleteStatementRule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+
+using namespace clang;
+using namespace tooling;
+
+Expected<DeleteStatementRule>
+DeleteStatementRule::initiate(RefactoringRuleContext &Context, Stmt *Stmt) {
+  return DeleteStatementRule(std::move(Stmt));
+}
+
+const RefactoringDescriptor &DeleteStatementRule::describe() {
+  static const RefactoringDescriptor Descriptor = {
+      "delete-statement",
+      "Delete Statement",
+      "Deletes stmts from code",
+  };
+  return Descriptor;
+}
+
+Expected<AtomicChanges>
+DeleteStatementRule::createSourceReplacements(RefactoringRuleContext &Context) {
+  // Compute the source range of the code that should be deleted.
+  SourceRange DeleteRange(Statement->getBeginLoc(),
+                             Statement->getEndLoc());
+
+  ASTContext &AST = Context.getASTContext();
+  SourceManager &SM = AST.getSourceManager();
+  const LangOptions &LangOpts = AST.getLangOpts();
+  Rewriter DeleteCodeRewriter(SM, LangOpts);
+
+  PrintingPolicy PP = AST.getPrintingPolicy();
+  PP.SuppressStrongLifetime = true;
+  PP.SuppressLifetimeQualifiers = true;
+  PP.SuppressUnwrittenScope = true;
+
+  AtomicChange Change(SM, Statement->getBeginLoc());
+  // Create the replacement for deleting statement
+  {
+    auto Err = Change.replace(
+        SM, CharSourceRange::getTokenRange(DeleteRange), "");
+    if (Err)
+      return std::move(Err);
+  }
+
+  return AtomicChanges{std::move(Change)};
+}



More information about the cfe-commits mailing list