[clang] 9945bd5 - Add Metadata to Transformer tooling

Yitzhak Mandelbaum via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 30 08:03:24 PDT 2020


Author: Andy Soffer
Date: 2020-06-30T15:03:07Z
New Revision: 9945bd5911636e7f821ac82fdcf8fdb22126e7dc

URL: https://github.com/llvm/llvm-project/commit/9945bd5911636e7f821ac82fdcf8fdb22126e7dc
DIFF: https://github.com/llvm/llvm-project/commit/9945bd5911636e7f821ac82fdcf8fdb22126e7dc.diff

LOG: Add Metadata to Transformer tooling

This change adds a Metadata field to ASTEdit, Edit, and AtomicChange so that
edits can have associated metadata and that metadata can be constructed with
Transformer-based RewriteRules. Metadata is ignored when applying edits to
source, but other consumers of AtomicChange can use this metadata to direct how
they want to consume each edit.

Reviewed By: ymandel, gribozavr2

Differential Revision: https://reviews.llvm.org/D82226

Added: 
    

Modified: 
    clang/include/clang/Tooling/Refactoring/AtomicChange.h
    clang/include/clang/Tooling/Transformer/RewriteRule.h
    clang/lib/Tooling/Refactoring/AtomicChange.cpp
    clang/lib/Tooling/Transformer/RewriteRule.cpp
    clang/lib/Tooling/Transformer/Transformer.cpp
    clang/unittests/Tooling/RefactoringTest.cpp
    clang/unittests/Tooling/TransformerTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/Refactoring/AtomicChange.h b/clang/include/clang/Tooling/Refactoring/AtomicChange.h
index 7cb9987e80c7..f1034a3d0579 100644
--- a/clang/include/clang/Tooling/Refactoring/AtomicChange.h
+++ b/clang/include/clang/Tooling/Refactoring/AtomicChange.h
@@ -17,6 +17,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Format/Format.h"
 #include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/Any.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 
@@ -41,6 +42,9 @@ class AtomicChange {
   /// is being changed, e.g. the call to a refactored method.
   AtomicChange(const SourceManager &SM, SourceLocation KeyPosition);
 
+  AtomicChange(const SourceManager &SM, SourceLocation KeyPosition,
+               llvm::Any Metadata);
+
   /// Creates an atomic change for \p FilePath with a customized key.
   AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key)
       : Key(Key), FilePath(FilePath) {}
@@ -120,6 +124,8 @@ class AtomicChange {
     return RemovedHeaders;
   }
 
+  const llvm::Any &getMetadata() const { return Metadata; }
+
 private:
   AtomicChange() {}
 
@@ -135,6 +141,12 @@ class AtomicChange {
   std::vector<std::string> InsertedHeaders;
   std::vector<std::string> RemovedHeaders;
   tooling::Replacements Replaces;
+
+  // This field stores metadata which is ignored for the purposes of applying
+  // edits to source, but may be useful for other consumers of AtomicChanges. In
+  // particular, consumers can use this to direct how they want to consume each
+  // edit.
+  llvm::Any Metadata;
 };
 
 using AtomicChanges = std::vector<AtomicChange>;

diff  --git a/clang/include/clang/Tooling/Transformer/RewriteRule.h b/clang/include/clang/Tooling/Transformer/RewriteRule.h
index 0a961ccc475d..d9e68717d5c8 100644
--- a/clang/include/clang/Tooling/Transformer/RewriteRule.h
+++ b/clang/include/clang/Tooling/Transformer/RewriteRule.h
@@ -21,6 +21,7 @@
 #include "clang/Tooling/Refactoring/AtomicChange.h"
 #include "clang/Tooling/Transformer/MatchConsumer.h"
 #include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/ADT/Any.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Error.h"
@@ -35,6 +36,7 @@ namespace transformer {
 struct Edit {
   CharSourceRange Range;
   std::string Replacement;
+  llvm::Any Metadata;
 };
 
 /// Maps a match result to a list of concrete edits (with possible
@@ -85,6 +87,7 @@ struct ASTEdit {
   RangeSelector TargetRange;
   TextGenerator Replacement;
   TextGenerator Note;
+  llvm::Any Metadata;
 };
 
 /// Lifts a list of `ASTEdit`s into an `EditGenerator`.
@@ -258,6 +261,11 @@ inline ASTEdit insertAfter(RangeSelector S, TextGenerator Replacement) {
 /// Removes the source selected by \p S.
 ASTEdit remove(RangeSelector S);
 
+inline ASTEdit withMetadata(ASTEdit edit, llvm::Any Metadata) {
+  edit.Metadata = std::move(Metadata);
+  return edit;
+}
+
 /// The following three functions are a low-level part of the RewriteRule
 /// API. We expose them for use in implementing the fixtures that interpret
 /// RewriteRule, like Transformer and TransfomerTidy, or for more advanced

diff  --git a/clang/lib/Tooling/Refactoring/AtomicChange.cpp b/clang/lib/Tooling/Refactoring/AtomicChange.cpp
index 3be15b7d8509..069e9c1eb36e 100644
--- a/clang/lib/Tooling/Refactoring/AtomicChange.cpp
+++ b/clang/lib/Tooling/Refactoring/AtomicChange.cpp
@@ -204,6 +204,12 @@ AtomicChange::AtomicChange(const SourceManager &SM,
   Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);
 }
 
+AtomicChange::AtomicChange(const SourceManager &SM, SourceLocation KeyPosition,
+                           llvm::Any M)
+    : AtomicChange(SM, KeyPosition) {
+  Metadata = std::move(M);
+}
+
 AtomicChange::AtomicChange(std::string Key, std::string FilePath,
                            std::string Error,
                            std::vector<std::string> InsertedHeaders,

diff  --git a/clang/lib/Tooling/Transformer/RewriteRule.cpp b/clang/lib/Tooling/Transformer/RewriteRule.cpp
index ddce6ce59185..995bec03cd66 100644
--- a/clang/lib/Tooling/Transformer/RewriteRule.cpp
+++ b/clang/lib/Tooling/Transformer/RewriteRule.cpp
@@ -47,6 +47,7 @@ translateEdits(const MatchResult &Result, ArrayRef<ASTEdit> ASTEdits) {
     transformer::Edit T;
     T.Range = *EditRange;
     T.Replacement = std::move(*Replacement);
+    T.Metadata = E.Metadata;
     Edits.push_back(std::move(T));
   }
   return Edits;

diff  --git a/clang/lib/Tooling/Transformer/Transformer.cpp b/clang/lib/Tooling/Transformer/Transformer.cpp
index 71340bf2f676..e8fc00c4e953 100644
--- a/clang/lib/Tooling/Transformer/Transformer.cpp
+++ b/clang/lib/Tooling/Transformer/Transformer.cpp
@@ -53,7 +53,7 @@ void Transformer::run(const MatchFinder::MatchResult &Result) {
     auto ID = Result.SourceManager->getFileID(T.Range.getBegin());
     auto Iter = ChangesByFileID
                     .emplace(ID, AtomicChange(*Result.SourceManager,
-                                              T.Range.getBegin()))
+                                              T.Range.getBegin(), T.Metadata))
                     .first;
     auto &AC = Iter->second;
     if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {

diff  --git a/clang/unittests/Tooling/RefactoringTest.cpp b/clang/unittests/Tooling/RefactoringTest.cpp
index d65c6dba77b2..97a26a71deec 100644
--- a/clang/unittests/Tooling/RefactoringTest.cpp
+++ b/clang/unittests/Tooling/RefactoringTest.cpp
@@ -1296,6 +1296,18 @@ TEST_F(AtomicChangeTest, InsertAfterWithInvalidLocation) {
       Replacement(Context.Sources, SourceLocation(), 0, "b")));
 }
 
+TEST_F(AtomicChangeTest, Metadata) {
+  AtomicChange Change(Context.Sources, DefaultLoc, 17);
+  const llvm::Any &Metadata = Change.getMetadata();
+  ASSERT_TRUE(llvm::any_isa<int>(Metadata));
+  EXPECT_EQ(llvm::any_cast<int>(Metadata), 17);
+}
+
+TEST_F(AtomicChangeTest, NoMetadata) {
+  AtomicChange Change(Context.Sources, DefaultLoc);
+  EXPECT_FALSE(Change.getMetadata().hasValue());
+}
+
 class ApplyAtomicChangesTest : public ::testing::Test {
 protected:
   ApplyAtomicChangesTest() : FilePath("file.cc") {

diff  --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp
index d19f747a69b5..7d6b63293748 100644
--- a/clang/unittests/Tooling/TransformerTest.cpp
+++ b/clang/unittests/Tooling/TransformerTest.cpp
@@ -439,6 +439,29 @@ TEST_F(TransformerTest, RemoveEdit) {
       Input, Expected);
 }
 
+TEST_F(TransformerTest, WithMetadata) {
+  std::string Input = R"cc(
+    int f() {
+      int x = 5;
+      return 7;
+    }
+  )cc";
+
+  Transformer T(
+      makeRule(declStmt().bind("decl"),
+               withMetadata(remove(statement(std::string("decl"))), 17)),
+      consumer());
+  T.registerMatchers(&MatchFinder);
+  auto Factory = newFrontendActionFactory(&MatchFinder);
+  EXPECT_TRUE(runToolOnCodeWithArgs(
+      Factory->create(), Input, std::vector<std::string>(), "input.cc",
+      "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
+  ASSERT_EQ(Changes.size(), 1u);
+  const llvm::Any &Metadata = Changes[0].getMetadata();
+  ASSERT_TRUE(llvm::any_isa<int>(Metadata));
+  EXPECT_THAT(llvm::any_cast<int>(Metadata), 17);
+}
+
 TEST_F(TransformerTest, MultiChange) {
   std::string Input = R"cc(
     void foo() {


        


More information about the cfe-commits mailing list