diff options
-rw-r--r-- | clang/docs/ClangFormatStyleOptions.rst | 9 | ||||
-rw-r--r-- | clang/include/clang/Tooling/Inclusions/HeaderIncludes.h | 1 | ||||
-rw-r--r-- | clang/include/clang/Tooling/Inclusions/IncludeStyle.h | 2 | ||||
-rw-r--r-- | clang/lib/Format/Format.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Tooling/Inclusions/HeaderIncludes.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Tooling/Inclusions/IncludeStyle.cpp | 1 | ||||
-rw-r--r-- | clang/unittests/Format/SortIncludesTest.cpp | 71 |
7 files changed, 108 insertions, 4 deletions
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 6a42da71b96..bd50943dfd8 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1511,6 +1511,13 @@ the configuration (without a prefix: ``Auto``). can also assign negative priorities if you have certain headers that always need to be first. + There is a third and optional field ``SortPriority`` which can used while + ``IncludeBloks = IBS_Regroup`` to define the priority in which ``#includes`` + should be ordered, and value of ``Priority`` defines the order of + ``#include blocks`` and also enables to group ``#includes`` of different + priority for order.``SortPriority`` is set to the value of ``Priority`` + as default if it is not assigned. + To configure this in the .clang-format file, use: .. code-block:: yaml @@ -1518,12 +1525,14 @@ the configuration (without a prefix: ``Auto``). IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 + SortPriority: 2 - Regex: '^(<|"(gtest|gmock|isl|json)/)' Priority: 3 - Regex: '<[[:alnum:].]+>' Priority: 4 - Regex: '.*' Priority: 1 + SortPriority: 0 **IncludeIsMainRegex** (``std::string``) Specify a regular expression of suffixes that are allowed in the diff --git a/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h b/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h index ec6f0ea45ff..6e6d6d8fb02 100644 --- a/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h +++ b/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h @@ -32,6 +32,7 @@ public: /// 0. Otherwise, returns the priority of the matching category or INT_MAX. /// NOTE: this API is not thread-safe! int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) const; + int getSortIncludePriority(StringRef IncludeName, bool CheckMainHeader) const; private: bool isMainHeader(StringRef IncludeName) const; diff --git a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h index a0f236e6fc4..266763a5b1b 100644 --- a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h +++ b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h @@ -58,6 +58,8 @@ struct IncludeStyle { std::string Regex; /// The priority to assign to this category. int Priority; + /// The custom priority to sort before grouping. + int SortPriority; bool operator==(const IncludeCategory &Other) const { return Regex == Other.Regex && Priority == Other.Priority; } diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index ba76ba083a6..b64d4825240 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1771,6 +1771,7 @@ struct IncludeDirective { StringRef Text; unsigned Offset; int Category; + int Priority; }; struct JavaImportDirective { @@ -1834,6 +1835,7 @@ static void sortCppIncludes(const FormatStyle &Style, ArrayRef<tooling::Range> Ranges, StringRef FileName, StringRef Code, tooling::Replacements &Replaces, unsigned *Cursor) { + tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName); unsigned IncludesBeginOffset = Includes.front().Offset; unsigned IncludesEndOffset = Includes.back().Offset + Includes.back().Text.size(); @@ -1841,11 +1843,12 @@ static void sortCppIncludes(const FormatStyle &Style, if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset)) return; SmallVector<unsigned, 16> Indices; - for (unsigned i = 0, e = Includes.size(); i != e; ++i) + 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].Category, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Category, Includes[RHSI].Filename); + 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. @@ -1960,9 +1963,12 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, int Category = Categories.getIncludePriority( IncludeName, /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock); + int Priority = Categories.getSortIncludePriority( + IncludeName, !MainIncludeFound && FirstIncludeBlock); if (Category == 0) MainIncludeFound = true; - IncludesInBlock.push_back({IncludeName, Line, Prev, Category}); + IncludesInBlock.push_back( + {IncludeName, Line, Prev, Category, Priority}); } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) { sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, Replaces, Cursor); diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp index a7f79c33bc5..e746bbb7f87 100644 --- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -199,6 +199,20 @@ int IncludeCategoryManager::getIncludePriority(StringRef IncludeName, return Ret; } +int IncludeCategoryManager::getSortIncludePriority(StringRef IncludeName, + bool CheckMainHeader) const { + int Ret = INT_MAX; + for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i) + if (CategoryRegexs[i].match(IncludeName)) { + Ret = Style.IncludeCategories[i].SortPriority; + if (Ret == 0) + Ret = Style.IncludeCategories[i].Priority; + break; + } + if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName)) + Ret = 0; + return Ret; +} bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const { if (!IncludeName.startswith("\"")) return false; diff --git a/clang/lib/Tooling/Inclusions/IncludeStyle.cpp b/clang/lib/Tooling/Inclusions/IncludeStyle.cpp index c53c82c8363..26dc0b87cf9 100644 --- a/clang/lib/Tooling/Inclusions/IncludeStyle.cpp +++ b/clang/lib/Tooling/Inclusions/IncludeStyle.cpp @@ -17,6 +17,7 @@ void MappingTraits<IncludeStyle::IncludeCategory>::mapping( IO &IO, IncludeStyle::IncludeCategory &Category) { IO.mapOptional("Regex", Category.Regex); IO.mapOptional("Priority", Category.Priority); + IO.mapOptional("SortPriority", Category.SortPriority); } void ScalarEnumerationTraits<IncludeStyle::IncludeBlocksStyle>::enumeration( diff --git a/clang/unittests/Format/SortIncludesTest.cpp b/clang/unittests/Format/SortIncludesTest.cpp index c00d3cb747d..ef67586f1f0 100644 --- a/clang/unittests/Format/SortIncludesTest.cpp +++ b/clang/unittests/Format/SortIncludesTest.cpp @@ -70,6 +70,77 @@ TEST_F(SortIncludesTest, BasicSorting) { {tooling::Range(25, 1)})); } +TEST_F(SortIncludesTest, SortedIncludesUsingSortPriorityAttribute) { + FmtStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; + FmtStyle.IncludeStyle.IncludeCategories = { + {"^<sys/param\\.h>", 1, 0}, + {"^<sys/types\\.h>", 1, 1}, + {"^<sys.*/", 1, 2}, + {"^<uvm/", 2, 3}, + {"^<machine/", 3, 4}, + {"^<dev/", 4, 5}, + {"^<net.*/", 5, 6}, + {"^<protocols/", 5, 7}, + {"^<(fs|miscfs|msdosfs|nfs|ntfs|ufs)/", 6, 8}, + {"^<(x86|amd64|i386|xen)/", 7, 8}, + {"<path", 9, 11}, + {"^<[^/].*\\.h>", 8, 10}, + {"^\".*\\.h\"", 10, 12}}; + EXPECT_EQ("#include <sys/param.h>\n" + "#include <sys/types.h>\n" + "#include <sys/ioctl.h>\n" + "#include <sys/socket.h>\n" + "#include <sys/stat.h>\n" + "#include <sys/wait.h>\n" + "\n" + "#include <net/if.h>\n" + "#include <net/if_dl.h>\n" + "#include <net/route.h>\n" + "#include <netinet/in.h>\n" + "#include <protocols/rwhod.h>\n" + "\n" + "#include <assert.h>\n" + "#include <errno.h>\n" + "#include <inttypes.h>\n" + "#include <stdio.h>\n" + "#include <stdlib.h>\n" + "\n" + "#include <paths.h>\n" + "\n" + "#include \"pathnames.h\"\n", + sort("#include <sys/param.h>\n" + "#include <sys/types.h>\n" + "#include <sys/ioctl.h>\n" + "#include <net/if_dl.h>\n" + "#include <net/route.h>\n" + "#include <netinet/in.h>\n" + "#include <sys/socket.h>\n" + "#include <sys/stat.h>\n" + "#include <sys/wait.h>\n" + "#include <net/if.h>\n" + "#include <protocols/rwhod.h>\n" + "#include <assert.h>\n" + "#include <paths.h>\n" + "#include \"pathnames.h\"\n" + "#include <errno.h>\n" + "#include <inttypes.h>\n" + "#include <stdio.h>\n" + "#include <stdlib.h>\n")); +} +TEST_F(SortIncludesTest, SortPriorityNotDefined) { + FmtStyle = getLLVMStyle(); + EXPECT_EQ("#include \"FormatTestUtils.h\"\n" + "#include \"clang/Format/Format.h\"\n" + "#include \"llvm/ADT/None.h\"\n" + "#include \"llvm/Support/Debug.h\"\n" + "#include \"gtest/gtest.h\"\n", + sort("#include \"clang/Format/Format.h\"\n" + "#include \"llvm/ADT/None.h\"\n" + "#include \"FormatTestUtils.h\"\n" + "#include \"gtest/gtest.h\"\n" + "#include \"llvm/Support/Debug.h\"\n")); +} + TEST_F(SortIncludesTest, NoReplacementsForValidIncludes) { // Identical #includes have led to a failure with an unstable sort. std::string Code = "#include <a>\n" |