]> granicus.if.org Git - clang/commitdiff
Tooling: Ignore file names in tooling::deduplicate.
authorBenjamin Kramer <benny.kra@googlemail.com>
Tue, 9 Sep 2014 13:53:29 +0000 (13:53 +0000)
committerBenjamin Kramer <benny.kra@googlemail.com>
Tue, 9 Sep 2014 13:53:29 +0000 (13:53 +0000)
This was horribly broken due to how the sort predicate works. We would
report a conflict for files with a replacement in the same position but
different names if the length differed. Just ignore paths as this is often
what the user wants. Files can occur with different names (due to symlinks
or relative paths) and we don't ever want to do the same edit in one file
twice.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217439 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Tooling/Refactoring.h
lib/Tooling/Refactoring.cpp
unittests/Tooling/RefactoringTest.cpp

index cd2fb9f6c563c9c949eeda869ad0bce989cf96e0..3acf16b4247e73bcf87e040b72e3dc0c5a19c5ce 100644 (file)
@@ -171,7 +171,7 @@ unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
                              unsigned Position);
 
 /// \brief Removes duplicate Replacements and reports if Replacements conflict
-/// with one another.
+/// with one another. All Replacements are assumed to be in the same file.
 ///
 /// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
 ///
index b2a02cb0964cb5f8f3f2fc8a0f789f0926d6c7ae..1dadaa7a384c6ba6dfed7c57df9d6a36cbc14c06 100644 (file)
@@ -238,11 +238,25 @@ void deduplicate(std::vector<Replacement> &Replaces,
   if (Replaces.empty())
     return;
 
-  // Deduplicate
-  std::sort(Replaces.begin(), Replaces.end());
-  std::vector<Replacement>::iterator End =
-      std::unique(Replaces.begin(), Replaces.end());
-  Replaces.erase(End, Replaces.end());
+  auto LessNoPath = [](const Replacement &LHS, const Replacement &RHS) {
+    if (LHS.getOffset() != RHS.getOffset())
+      return LHS.getOffset() < RHS.getOffset();
+    if (LHS.getLength() != RHS.getLength())
+      return LHS.getLength() < RHS.getLength();
+    return LHS.getReplacementText() < RHS.getReplacementText();
+  };
+
+  auto EqualNoPath = [](const Replacement &LHS, const Replacement &RHS) {
+    return LHS.getOffset() == RHS.getOffset() &&
+           LHS.getLength() == RHS.getLength() &&
+           LHS.getReplacementText() == RHS.getReplacementText();
+  };
+
+  // Deduplicate. We don't want to deduplicate based on the path as we assume
+  // that all replacements refer to the same file (or are symlinks).
+  std::sort(Replaces.begin(), Replaces.end(), LessNoPath);
+  Replaces.erase(std::unique(Replaces.begin(), Replaces.end(), EqualNoPath),
+                 Replaces.end());
 
   // Detect conflicts
   Range ConflictRange(Replaces.front().getOffset(),
index 3e067dd3f99d076a7e049818975c9ab3a90ea16c..73c53aa842a7c43c11912165ea2523a9225acb6f 100644 (file)
@@ -393,6 +393,8 @@ TEST(DeduplicateTest, removesDuplicates) {
   Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate
   Input.push_back(Replacement("fileA", 51, 3, " bar "));
   Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs!
+  Input.push_back(Replacement("fileB", 60, 1, " bar "));
+  Input.push_back(Replacement("fileA", 60, 2, " bar "));
   Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text
                                                          // differs!
 
@@ -403,12 +405,14 @@ TEST(DeduplicateTest, removesDuplicates) {
   Expected.push_back(Replacement("fileA", 50, 0, " foo "));
   Expected.push_back(Replacement("fileA", 51, 3, " bar "));
   Expected.push_back(Replacement("fileA", 51, 3, " moo "));
-  Expected.push_back(Replacement("fileB", 51, 3, " bar "));
+  Expected.push_back(Replacement("fileB", 60, 1, " bar "));
+  Expected.push_back(Replacement("fileA", 60, 2, " bar "));
 
   std::vector<Range> Conflicts; // Ignored for this test
   deduplicate(Input, Conflicts);
 
-  ASSERT_TRUE(Expected == Input);
+  EXPECT_EQ(3U, Conflicts.size());
+  EXPECT_EQ(Expected, Input);
 }
 
 TEST(DeduplicateTest, detectsConflicts) {