Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -2072,6 +2072,10 @@ /// http://www.gnu.org/prep/standards/standards.html FormatStyle getGNUStyle(); +/// Returns a format style complying with NetBSD Coding Standards: +/// http://cvsweb.netbsd.org/bsdweb.cgi/src/share/misc/style?rev=HEAD&content-type=text/x-cvsweb-markup +FormatStyle getNetBSDStyle(); + /// Returns style indicating formatting should be not applied at all. FormatStyle getNoStyle(); Index: include/clang/Tooling/Inclusions/HeaderIncludes.h =================================================================== --- include/clang/Tooling/Inclusions/HeaderIncludes.h +++ include/clang/Tooling/Inclusions/HeaderIncludes.h @@ -32,7 +32,7 @@ /// 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; Index: include/clang/Tooling/Inclusions/IncludeStyle.h =================================================================== --- include/clang/Tooling/Inclusions/IncludeStyle.h +++ include/clang/Tooling/Inclusions/IncludeStyle.h @@ -58,6 +58,8 @@ 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; } Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -1023,6 +1023,39 @@ return Style; } +FormatStyle getNetBSDStyle() { + FormatStyle NetBSDStyle = getLLVMStyle(); + NetBSDStyle.AlignTrailingComments = true; + NetBSDStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; + NetBSDStyle.AlignConsecutiveMacros = true; + NetBSDStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; + NetBSDStyle.ColumnLimit = 80; + NetBSDStyle.ContinuationIndentWidth = 4; + NetBSDStyle.Cpp11BracedListStyle = false; + NetBSDStyle.FixNamespaceComments = true; + NetBSDStyle.IndentCaseLabels = false; + NetBSDStyle.IndentWidth = 8; + NetBSDStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; + NetBSDStyle.IncludeStyle.IncludeCategories = { + {"^", 1, 0}, + {"^", 1, 1}, + {"^", 8, 10}, + {"^\".*\\.h\"", 10, 12}}; + NetBSDStyle.SortIncludes = true; + NetBSDStyle.TabWidth = 8; + NetBSDStyle.UseTab = FormatStyle::UT_Always; + return NetBSDStyle; +} + FormatStyle getNoStyle() { FormatStyle NoStyle = getLLVMStyle(); NoStyle.DisableFormat = true; @@ -1047,6 +1080,8 @@ *Style = getGNUStyle(); } else if (Name.equals_lower("microsoft")) { *Style = getMicrosoftStyle(Language); + } else if (Name.equals_lower("netbsd")) { + *Style = getNetBSDStyle(); } else if (Name.equals_lower("none")) { *Style = getNoStyle(); } else { @@ -1714,6 +1749,7 @@ StringRef Text; unsigned Offset; int Category; + int Priority; }; struct JavaImportDirective { @@ -1777,6 +1813,7 @@ ArrayRef 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(); @@ -1784,11 +1821,15 @@ if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset)) return; SmallVector Indices; - for (unsigned i = 0, e = Includes.size(); i != e; ++i) + SmallVector IncludesPriority; + for (unsigned i = 0, e = Includes.size(); i != e; ++i) { + // IncludesPriority.push_back( + // Categories.getSortIncludePriority(Includes[i].Filename)); 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. @@ -1903,9 +1944,12 @@ 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); Index: lib/Tooling/Inclusions/HeaderIncludes.cpp =================================================================== --- lib/Tooling/Inclusions/HeaderIncludes.cpp +++ lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -199,6 +199,19 @@ 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; Index: lib/Tooling/Inclusions/IncludeStyle.cpp =================================================================== --- lib/Tooling/Inclusions/IncludeStyle.cpp +++ lib/Tooling/Inclusions/IncludeStyle.cpp @@ -17,6 +17,7 @@ IO &IO, IncludeStyle::IncludeCategory &Category) { IO.mapOptional("Regex", Category.Regex); IO.mapOptional("Priority", Category.Priority); + IO.mapOptional("SortPriority", Category.SortPriority); } void ScalarEnumerationTraits::enumeration( Index: unittests/Format/SortIncludesTest.cpp =================================================================== --- unittests/Format/SortIncludesTest.cpp +++ unittests/Format/SortIncludesTest.cpp @@ -70,6 +70,79 @@ {tooling::Range(25, 1)})); } +TEST_F(SortIncludesTest, ParamAndTypesCheck) { + FmtStyle = getNetBSDStyle(); + EXPECT_EQ("#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n", + sort("#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n")); + +} + +TEST_F(SortIncludesTest, SortedIncludesUsingSortPriorityAttribute) { + FmtStyle = getNetBSDStyle(); + EXPECT_EQ("#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "\n" + "#include \n" + "\n" + "#include \"pathnames.h\"\n", + sort("#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \"pathnames.h\"\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n")); + + 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 \n"