Author: Lukas Barth Date: 2021-01-25T18:53:22+01:00 New Revision: 3395a336b02538d0bb768ccfae11c9b6151b102e
URL: https://github.com/llvm/llvm-project/commit/3395a336b02538d0bb768ccfae11c9b6151b102e DIFF: https://github.com/llvm/llvm-project/commit/3395a336b02538d0bb768ccfae11c9b6151b102e.diff LOG: [clang-format] add case aware include sorting * Adds an option to [clang-format] which sorts headers in an alphabetical manner using case only for tie-breakers. The options is off by default in favor of the current ASCIIbetical sorting style. Reviewed By: curdeius, HazardyKnusperkeks Differential Revision: https://reviews.llvm.org/D95017 Added: Modified: clang/docs/ClangFormatStyleOptions.rst clang/include/clang/Tooling/Inclusions/IncludeStyle.h clang/lib/Format/Format.cpp clang/unittests/Format/FormatTest.cpp clang/unittests/Format/SortIncludesTest.cpp Removed: ################################################################################ diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 3141dd5510fc..d5ce1b7b2e8e 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2282,6 +2282,26 @@ the configuration (without a prefix: ``Auto``). ``ClassImpl.hpp`` would not have the main include file put on top before any other include. +**IncludeSortAlphabetically** (``bool``) + Specify if sorting should be done in an alphabetical and + case sensitive fashion. + + When ``false``, includes are sorted in an ASCIIbetical + fashion. + When ``true``, includes are sorted in an alphabetical + fashion with case used as a tie-breaker. + + .. code-block:: c++ + + false: true: + #include "A/B.h" vs. #include "A/B.h" + #include "A/b.h" #include "A/b.h" + #include "B/A.h" #include "a/b.h" + #include "B/a.h" #include "B/A.h" + #include "a/b.h" #include "B/a.h" + + This option is off by default. + **IndentCaseBlocks** (``bool``) Indent case label blocks one level from the case label. diff --git a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h index 4caaf4121f15..652a7b61a0a4 100644 --- a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h +++ b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h @@ -147,6 +147,26 @@ struct IncludeStyle { /// ``ClassImpl.hpp`` would not have the main include file put on top /// before any other include. std::string IncludeIsMainSourceRegex; + + /// Specify if sorting should be done in an alphabetical and + /// case sensitive fashion. + /// + /// When ``false``, includes are sorted in an ASCIIbetical + /// fashion. + /// When ``true``, includes are sorted in an alphabetical + /// fashion with case used as a tie-breaker. + /// + /// \code + /// false: true: + /// #include "A/B.h" vs. #include "A/B.h" + /// #include "A/b.h" #include "A/b.h" + /// #include "B/A.h" #include "a/b.h" + /// #include "B/a.h" #include "B/A.h" + /// #include "a/b.h" #include "B/a.h" + /// \endcode + /// + /// This option is off by default. + bool IncludeSortAlphabetically; }; } // namespace tooling diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index cd1c6e4f6023..0986ef845a4e 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -571,6 +571,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); + IO.mapOptional("IncludeSortAlphabetically", + Style.IncludeStyle.IncludeSortAlphabetically); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); @@ -940,6 +942,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { {".*", 1, 0, false}}; LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; + LLVMStyle.IncludeStyle.IncludeSortAlphabetically = false; LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentCaseBlocks = false; LLVMStyle.IndentGotoLabels = true; @@ -2194,10 +2197,23 @@ static void sortCppIncludes(const FormatStyle &Style, for (unsigned i = 0, e = Includes.size(); i != e; ++i) { Indices.push_back(i); } - llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); - }); + + if (Style.IncludeStyle.IncludeSortAlphabetically) { + llvm::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 { + llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { + return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < + std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); + }); + } + // The index of the include on which the cursor will be put after // sorting/deduplicating. unsigned CursorIndex; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 0c37d1188f15..cbb368d4f605 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -15145,6 +15145,8 @@ TEST_F(FormatTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(DeriveLineEnding); CHECK_PARSE_BOOL(DerivePointerAlignment); CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); + CHECK_PARSE_BOOL_FIELD(IncludeStyle.IncludeSortAlphabetically, + "IncludeSortAlphabetically"); CHECK_PARSE_BOOL(DisableFormat); CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentCaseBlocks); diff --git a/clang/unittests/Format/SortIncludesTest.cpp b/clang/unittests/Format/SortIncludesTest.cpp index 41ff7afad10e..a506218f537d 100644 --- a/clang/unittests/Format/SortIncludesTest.cpp +++ b/clang/unittests/Format/SortIncludesTest.cpp @@ -598,6 +598,49 @@ TEST_F(SortIncludesTest, MainHeaderIsSeparatedWhenRegroupping) { "a.cc")); } +TEST_F(SortIncludesTest, SupportOptionalAlphabeticalSorting) { + EXPECT_FALSE(Style.IncludeSortAlphabetically); + + Style.IncludeSortAlphabetically = true; + + EXPECT_EQ("#include \"A/B.h\"\n" + "#include \"A/b.h\"\n" + "#include \"a/b.h\"\n" + "#include \"B/A.h\"\n" + "#include \"B/a.h\"\n", + sort("#include \"B/a.h\"\n" + "#include \"B/A.h\"\n" + "#include \"A/B.h\"\n" + "#include \"a/b.h\"\n" + "#include \"A/b.h\"\n", + "a.h")); + + Style.IncludeBlocks = clang::tooling::IncludeStyle::IBS_Regroup; + Style.IncludeCategories = { + {"^\"", 1, 0, false}, {"^<.*\\.h>$", 2, 0, false}, {"^<", 3, 0, false}}; + + StringRef UnsortedCode = "#include \"qt.h\"\n" + "#include <algorithm>\n" + "#include <qtwhatever.h>\n" + "#include <Qtwhatever.h>\n" + "#include <Algorithm>\n" + "#include \"vlib.h\"\n" + "#include \"Vlib.h\"\n" + "#include \"AST.h\"\n"; + + EXPECT_EQ("#include \"AST.h\"\n" + "#include \"qt.h\"\n" + "#include \"Vlib.h\"\n" + "#include \"vlib.h\"\n" + "\n" + "#include <Qtwhatever.h>\n" + "#include <qtwhatever.h>\n" + "\n" + "#include <Algorithm>\n" + "#include <algorithm>\n", + sort(UnsortedCode)); +} + TEST_F(SortIncludesTest, SupportCaseInsensitiveMatching) { // Setup an regex for main includes so we can cover those as well. Style.IncludeIsMainRegex = "([-_](test|unittest))?$"; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits