[PATCH] Templatize tooling::deduplicate()

Edwin Vane edwin.vane at intel.com
Thu Aug 15 12:54:01 PDT 2013


Hi klimek, silvas, djasper,

To facilitate deduplication of Replacements with extra data attached,
deduplicate() has been generalized to work on vectors of type T.
tooling::Replacement already satisfies all requirements of type T so no
changes to existing code are necessary.

http://llvm-reviews.chandlerc.com/D1415

Files:
  include/clang/Tooling/Refactoring.h
  lib/Tooling/Refactoring.cpp

Index: include/clang/Tooling/Refactoring.h
===================================================================
--- include/clang/Tooling/Refactoring.h
+++ include/clang/Tooling/Refactoring.h
@@ -114,14 +114,6 @@
   /// \brief Returns a human readable string representation.
   std::string toString() const;
 
-  /// \brief Comparator to be able to use Replacement in std::set for uniquing.
-  class Less {
-  public:
-    bool operator()(const Replacement &R1, const Replacement &R2) const;
-  };
-
-  bool operator==(const Replacement &Other) const;
-
  private:
   void setFromSourceLocation(SourceManager &Sources, SourceLocation Start,
                              unsigned Length, StringRef ReplacementText);
@@ -133,9 +125,15 @@
   std::string ReplacementText;
 };
 
+/// \brief Less-than operator between two Replacements.
+bool operator<(const Replacement &LHS, const Replacement &RHS);
+
+/// \brief Equal-to operator between two Replacements.
+bool operator==(const Replacement &LHS, const Replacement &RHS);
+
 /// \brief A set of Replacements.
 /// FIXME: Change to a vector and deduplicate in the RefactoringTool.
-typedef std::set<Replacement, Replacement::Less> Replacements;
+typedef std::set<Replacement> Replacements;
 
 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
 ///
@@ -164,14 +162,6 @@
 /// applied.
 unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
 
-/// \brief Removes duplicate Replacements and reports if Replacements conflict
-/// with one another.
-///
-/// This function will sort \p Replaces so that conflicts can be reported simply
-/// by offset into \p Replaces and number of elements in the conflict.
-void deduplicate(std::vector<Replacement> &Replaces,
-                 std::vector<Range> &Conflicts);
-
 /// \brief A tool to run refactorings.
 ///
 /// This is a refactoring specific version of \see ClangTool. FrontendActions
@@ -217,6 +207,56 @@
   setFromSourceRange(Sources, Range, ReplacementText);
 }
 
+/// \brief Removes duplicates and reports conflicts between Replacement-like
+/// objects. If T == Replacement, no extra work is necessary to call this
+/// function. Otherwise, T must satisfy these requirements:
+/// \li operator== must exist to compare objects of type T
+/// \li operator< must exist to compare objects of type T
+/// \li T.getOffset() must exist and returns a file offset
+/// \li T.getLength() must exist and returns a source range length
+///
+/// This function will sort \p Replaces so that conflicts can be reported simply
+/// by offset into \p Replaces and number of elements in the conflict.
+template <typename T>
+void deduplicate(std::vector<T> &Replaces,
+                 std::vector<Range> &Conflicts) {
+  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());
+
+  // Detect conflicts
+  Range ConflictRange(Replaces.front().getOffset(),
+                      Replaces.front().getLength());
+  unsigned ConflictStart = 0;
+  unsigned ConflictLength = 1;
+  for (unsigned i = 1; i < Replaces.size(); ++i) {
+    Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
+    if (ConflictRange.overlapsWith(Current)) {
+      // Extend conflicted range
+      ConflictRange = Range(ConflictRange.getOffset(),
+                            std::max(ConflictRange.getLength(),
+                                     Current.getOffset() + Current.getLength() -
+                                         ConflictRange.getOffset()));
+      ++ConflictLength;
+    } else {
+      if (ConflictLength > 1)
+        Conflicts.push_back(Range(ConflictStart, ConflictLength));
+      ConflictRange = Current;
+      ConflictStart = i;
+      ConflictLength = 1;
+    }
+  }
+
+  if (ConflictLength > 1)
+    Conflicts.push_back(Range(ConflictStart, ConflictLength));
+}
+
+
 } // end namespace tooling
 } // end namespace clang
 
Index: lib/Tooling/Refactoring.cpp
===================================================================
--- lib/Tooling/Refactoring.cpp
+++ lib/Tooling/Refactoring.cpp
@@ -80,20 +80,21 @@
   return result;
 }
 
-bool Replacement::Less::operator()(const Replacement &R1,
-                                   const Replacement &R2) const {
-  if (R1.FilePath != R2.FilePath) return R1.FilePath < R2.FilePath;
-  if (R1.ReplacementRange.getOffset() != R2.ReplacementRange.getOffset())
-    return R1.ReplacementRange.getOffset() < R2.ReplacementRange.getOffset();
-  if (R1.ReplacementRange.getLength() != R2.ReplacementRange.getLength())
-    return R1.ReplacementRange.getLength() < R2.ReplacementRange.getLength();
-  return R1.ReplacementText < R2.ReplacementText;
+bool operator==(const Replacement &LHS, const Replacement &RHS) {
+  return LHS.getOffset() == RHS.getOffset() &&
+         LHS.getLength() == RHS.getLength() &&
+         LHS.getFilePath() == RHS.getFilePath() &&
+         LHS.getReplacementText() == RHS.getReplacementText();
 }
 
-bool Replacement::operator==(const Replacement &Other) const {
-  return ReplacementRange.getOffset() == Other.ReplacementRange.getOffset() &&
-         ReplacementRange.getLength() == Other.ReplacementRange.getLength() &&
-         FilePath == Other.FilePath && ReplacementText == Other.ReplacementText;
+bool operator<(const Replacement &LHS, const Replacement &RHS) {
+  if (LHS.getFilePath() != RHS.getFilePath())
+    return LHS.getFilePath() < RHS.getFilePath();
+  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();
 }
 
 void Replacement::setFromSourceLocation(SourceManager &Sources,
@@ -202,45 +203,6 @@
   return NewPosition;
 }
 
-void deduplicate(std::vector<Replacement> &Replaces,
-                 std::vector<Range> &Conflicts) {
-  if (Replaces.empty())
-    return;
-
-  // Deduplicate
-  std::sort(Replaces.begin(), Replaces.end(), Replacement::Less());
-  std::vector<Replacement>::iterator End =
-      std::unique(Replaces.begin(), Replaces.end());
-  Replaces.erase(End, Replaces.end());
-
-  // Detect conflicts
-  Range ConflictRange(Replaces.front().getOffset(),
-                      Replaces.front().getLength());
-  unsigned ConflictStart = 0;
-  unsigned ConflictLength = 1;
-  for (unsigned i = 1; i < Replaces.size(); ++i) {
-    Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
-    if (ConflictRange.overlapsWith(Current)) {
-      // Extend conflicted range
-      ConflictRange = Range(ConflictRange.getOffset(),
-                            std::max(ConflictRange.getLength(),
-                                     Current.getOffset() + Current.getLength() -
-                                         ConflictRange.getOffset()));
-      ++ConflictLength;
-    } else {
-      if (ConflictLength > 1)
-        Conflicts.push_back(Range(ConflictStart, ConflictLength));
-      ConflictRange = Current;
-      ConflictStart = i;
-      ConflictLength = 1;
-    }
-  }
-
-  if (ConflictLength > 1)
-    Conflicts.push_back(Range(ConflictStart, ConflictLength));
-}
-
-
 RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
                                  ArrayRef<std::string> SourcePaths)
   : ClangTool(Compilations, SourcePaths) {}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1415.1.patch
Type: text/x-patch
Size: 7506 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130815/4ecb2749/attachment.bin>


More information about the cfe-commits mailing list