https://github.com/DaanDeMeyer updated 
https://github.com/llvm/llvm-project/pull/137840

>From 33f84b217caab01a5ebbf93e4e5ac2182810c8db Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.deme...@gmail.com>
Date: Tue, 29 Apr 2025 18:26:36 +0200
Subject: [PATCH] clang-format: Add IgnoreExtension option to
 SortIncludesOptions

Sorting without taking the file extension into account gives nicer results
when various header file names are substrings of other header file names,
for example, a CLI application with a main header named analyze.h and a
analyze-xxx.h header for each subcommand currently will always put analyze.h
last after all the analyze-xxx.h headers, but putting analyze.h first instead
of last is arguable nicer to read.

TLDR; Instead of

"""
/#include "analyze-blame.h"
/#include "analyze.h"
"""

You'd get

"""
/#include "analyze.h"
/#include "analyze-blame.h"
"""

Let's allow sorting without taking the file extension into account unless two
headers otherwise compare equal by introducing a new boolean option 
IgnoreExtension
for SortIncludesOptions.
---
 clang/docs/ClangFormatStyleOptions.rst      | 11 +++++++
 clang/include/clang/Format/Format.h         | 11 ++++++-
 clang/lib/Format/Format.cpp                 | 34 +++++++++++++--------
 clang/unittests/Format/SortIncludesTest.cpp | 20 ++++++++++++
 4 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 83716cc049ee3..8ec658ef4b855 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -6010,6 +6010,17 @@ the configuration (without a prefix: ``Auto``).
        #include "B/A.h"           #include "B/a.h"
        #include "B/a.h"           #include "a/b.h"
 
+  * ``bool IgnoreExtension`` :versionbadge:`clang-format 21`
+  When sorting includes in each block, Only take file extensions into
+    account if two includes compare equal otherwise.
+
+    .. code-block:: c++
+
+       true:                      false:
+       # include "A.h"             # include "A-util.h"
+       # include "A.inc"           # include "A.h"
+       # include "A-util.h"        # include "A.inc"
+
 
 .. _SortJavaStaticImport:
 
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 3ac4318824ac0..18e314426c1ae 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -4382,8 +4382,17 @@ struct FormatStyle {
     ///    #include "B/a.h"           #include "a/b.h"
     /// \endcode
     bool IgnoreCase;
+    /// When sorting includes in each block, Only take file extensions into
+    /// account if two includes compare equal otherwise.
+    /// \code
+    ///    true:                      false:
+    ///    # include "A.h"             # include "A-util.h"
+    ///    # include "A.inc"           # include "A.h"
+    ///    # include "A-util.h"        # include "A.inc"
+    /// \version 21
+    bool IgnoreExtension;
     bool operator==(const SortIncludesOptions &R) const {
-      return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase;
+      return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase && 
IgnoreExtension == R.IgnoreExtension;
     }
     bool operator!=(const SortIncludesOptions &R) const {
       return !(*this == R);
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index b41a98ecb5be1..6bf951ff61bf0 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave;
   LLVMStyle.ShortNamespaceLines = 1;
   LLVMStyle.SkipMacroDefinitionBody = false;
-  LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false};
+  LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, 
/*IgnoreExtension=*/false};
   LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
   LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric;
   LLVMStyle.SpaceAfterCStyleCast = false;
@@ -3230,19 +3230,27 @@ static void sortCppIncludes(const FormatStyle &Style,
   SmallVector<unsigned, 16> Indices =
       llvm::to_vector<16>(llvm::seq<unsigned>(0, Includes.size()));
 
-  if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) {
+  if (Style.SortIncludes.Enabled) {
     stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) {
-      const auto LHSFilenameLower = Includes[LHSI].Filename.lower();
-      const auto RHSFilenameLower = Includes[RHSI].Filename.lower();
-      return std::tie(Includes[LHSI].Priority, LHSFilenameLower,
-                      Includes[LHSI].Filename) <
-             std::tie(Includes[RHSI].Priority, RHSFilenameLower,
-                      Includes[RHSI].Filename);
-    });
-  } else {
-    stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) {
-      return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) <
-             std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename);
+      SmallString<128> LHSStem, RHSStem;
+      if (Style.SortIncludes.IgnoreExtension) {
+        LHSStem = Includes[LHSI].Filename;
+        RHSStem = Includes[RHSI].Filename;
+        llvm::sys::path::replace_extension(LHSStem, "");
+        llvm::sys::path::replace_extension(RHSStem, "");
+      }
+      std::string LHSStemLower, RHSStemLower;
+      std::string LHSFilenameLower, RHSFilenameLower;
+      if (Style.SortIncludes.IgnoreCase) {
+        LHSStemLower = LHSStem.str().lower();
+        RHSStemLower = RHSStem.str().lower();
+        LHSFilenameLower = Includes[LHSI].Filename.lower();
+        RHSFilenameLower = Includes[RHSI].Filename.lower();
+      }
+      return std::tie(Includes[LHSI].Priority, LHSStemLower, LHSStem,
+                      LHSFilenameLower, Includes[LHSI].Filename) <
+            std::tie(Includes[RHSI].Priority, RHSStemLower, RHSStem,
+                      RHSFilenameLower, Includes[RHSI].Filename);
     });
   }
 
diff --git a/clang/unittests/Format/SortIncludesTest.cpp 
b/clang/unittests/Format/SortIncludesTest.cpp
index 994227efdd4f8..3e69ce56d98c5 100644
--- a/clang/unittests/Format/SortIncludesTest.cpp
+++ b/clang/unittests/Format/SortIncludesTest.cpp
@@ -1483,6 +1483,26 @@ TEST_F(SortIncludesTest, BlockCommentedOutIncludes) {
   verifyFormat(Code, sort(Code, "input.cpp", 0));
 }
 
+TEST_F(SortIncludesTest, IgnoreExtension) {
+  verifyFormat("#include <a-util.h>\n"
+               "#include <a.h>\n"
+               "#include <a.inc>",
+               sort("#include <a.inc>\n"
+                    "#include <a-util.h>\n"
+                    "#include <a.h>",
+                    "input.h", 1));
+
+  FmtStyle.SortIncludes.IgnoreExtension = true;
+
+  verifyFormat("#include <a.h>\n"
+               "#include <a.inc>\n"
+               "#include <a-util.h>",
+               sort("#include <a.inc>\n"
+                    "#include <a-util.h>\n"
+                    "#include <a.h>",
+                    "input.h", 1));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to