clang-format: Use stable_sort when sorting #includes.
authorDaniel Jasper <djasper@google.com>
Thu, 3 Mar 2016 17:34:14 +0000 (17:34 +0000)
committerDaniel Jasper <djasper@google.com>
Thu, 3 Mar 2016 17:34:14 +0000 (17:34 +0000)
Otherwise, clang-format can output useless replacements in the presence
of identical #includes

llvm-svn: 262630

clang/lib/Format/Format.cpp
clang/unittests/Format/SortIncludesTest.cpp

index c8f5ec9..91eac13 100644 (file)
@@ -1844,10 +1844,11 @@ static void sortIncludes(const FormatStyle &Style,
   SmallVector<unsigned, 16> Indices;
   for (unsigned i = 0, e = Includes.size(); i != e; ++i)
     Indices.push_back(i);
-  std::sort(Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
-    return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
-           std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
-  });
+  std::stable_sort(
+      Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) {
+        return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
+               std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
+      });
 
   // If the #includes are out of order, we generate a single replacement fixing
   // the entire block. Otherwise, no replacement is generated.
index dbe1174..9e5f267 100644 (file)
@@ -20,8 +20,12 @@ namespace {
 
 class SortIncludesTest : public ::testing::Test {
 protected:
-  std::string sort(llvm::StringRef Code, StringRef FileName = "input.cpp") {
-    std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+  std::vector<tooling::Range> GetCodeRange(StringRef Code) {
+    return std::vector<tooling::Range>(1, tooling::Range(0, Code.size()));
+  }
+
+  std::string sort(StringRef Code, StringRef FileName = "input.cpp") {
+    auto Ranges = GetCodeRange(Code);
     std::string Sorted =
         applyAllReplacements(Code, sortIncludes(Style, Code, Ranges, FileName));
     return applyAllReplacements(Sorted,
@@ -29,8 +33,7 @@ protected:
   }
 
   unsigned newCursor(llvm::StringRef Code, unsigned Cursor) {
-    std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
-    sortIncludes(Style, Code, Ranges, "input.cpp", &Cursor);
+    sortIncludes(Style, Code, GetCodeRange(Code), "input.cpp", &Cursor);
     return Cursor;
   }
 
@@ -47,6 +50,17 @@ TEST_F(SortIncludesTest, BasicSorting) {
                  "#include \"b.h\"\n"));
 }
 
+TEST_F(SortIncludesTest, NoReplacementsForValidIncludes) {
+  // Identical #includes have led to a failure with an unstable sort.
+  std::string Code = "#include <a>\n"
+                     "#include <b>\n"
+                     "#include <b>\n"
+                     "#include <b>\n"
+                     "#include <b>\n"
+                     "#include <c>\n";
+  EXPECT_TRUE(sortIncludes(Style, Code, GetCodeRange(Code), "a.cc").empty());
+}
+
 TEST_F(SortIncludesTest, SupportClangFormatOff) {
   EXPECT_EQ("#include <a>\n"
             "#include <b>\n"