Manikishan updated this revision to Diff 209814. Repository: rC Clang
CHANGES SINCE LAST ACTION https://reviews.llvm.org/D64695/new/ https://reviews.llvm.org/D64695 Files: docs/ClangFormatStyleOptions.rst include/clang/Format/Format.h lib/Format/Format.cpp unittests/Format/SortIncludesTest.cpp
Index: unittests/Format/SortIncludesTest.cpp =================================================================== --- unittests/Format/SortIncludesTest.cpp +++ unittests/Format/SortIncludesTest.cpp @@ -665,6 +665,67 @@ "#include \"a.h\"")); } +TEST_F(SortIncludesTest, ParamAndTypesCheck) { + FmtStyle = getNetBSDStyle(); + 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", + sort("#include <sys/ioctl.h>\n" + "#include <sys/stat.h>\n" + "#include <sys/socket.h>\n" + "#include <sys/types.h>\n" + "#include <sys/param.h>\n" + "#include <sys/wait.h>\n")); + +} + +TEST_F(SortIncludesTest, SortedIncludesInSingleBlockReGroupWithNetBSDSpecifications) { + FmtStyle = getNetBSDStyle(); + 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")); +} + } // end namespace } // end namespace format } // end namespace clang Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -479,6 +479,7 @@ IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReflowComments", Style.ReflowComments); IO.mapOptional("SortIncludes", Style.SortIncludes); + IO.mapOptional("SortNetBSDIncludes", Style.SortNetBSDIncludes); IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations); IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast); IO.mapOptional("SpaceAfterLogicalNot", Style.SpaceAfterLogicalNot); @@ -609,7 +610,7 @@ return Style; FormatStyle Expanded = Style; Expanded.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, + false, false, false, false, false, false, false, true, true, true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: @@ -1023,6 +1024,29 @@ 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 = { + {"^<sys/", 7}, {"^<uvm/", 6}, {"^<(net.*|protocols)/", 5}, + {"^<(fs*)", 4}, {"^<path*", 3}, {"^<[^\/].*\.h>", 2}, + {"^\"\w.*\.h\"$", 1}, {".*", 0}}; + NetBSDStyle.SortNetBSDIncludes = true; + NetBSDStyle.TabWidth = 8; + NetBSDStyle.UseTab = FormatStyle::UT_Always; + return NetBSDStyle; +} + FormatStyle getNoStyle() { FormatStyle NoStyle = getLLVMStyle(); NoStyle.DisableFormat = true; @@ -1047,6 +1071,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 { @@ -1763,7 +1789,163 @@ } return std::make_pair(CursorIndex, OffsetToEOL); } +enum CppIncludeHeadersKind { + IHK_KERNELHEADERS, + IHK_NETWORKHEADERS, + IHK_FILESYSHEADERS, + IHK_MACHINESHEADERS, + IHK_ARCHHEADERS, + IHK_USERHEADERS, + IHK_INCLUDESWITHQUOTES, +}; + +CppIncludeHeadersKind getHeadersKind(std::string Filename) { + SmallVector<StringRef, 4> Matches; + const char KernelHeaderPattern[] = R"(^<(sys.*|uvm|dev)/)"; + const char NetworkHeaderPattern[] = R"(^<(net.*|protocols)/)"; + const char FilesSystemHeaderPattern[] = + R"(^<(fs|miscfs|msdosfs|nfs|ntfs|ufs))"; + const char MachineHeaderPattern[] = R"(^<machine/)"; + const char ArchHeadersPattern[] = R"(^<(x86|amd64|i386|xen)/)"; + const char UserHeaderPattern[] = R"(^<[a-zA-Z0-9]*\.h>)"; + const char IncludeWithQuotesPattern[] = R"(^\"*$\")"; + llvm::Regex MatchKernel = llvm::Regex(KernelHeaderPattern); + llvm::Regex MatchNetwork = llvm::Regex(NetworkHeaderPattern); + llvm::Regex MatchFileSys = llvm::Regex(FilesSystemHeaderPattern); + llvm::Regex MatchMachine = llvm::Regex(MachineHeaderPattern); + llvm::Regex MatchArch = llvm::Regex(ArchHeadersPattern); + llvm::Regex MatchUser = llvm::Regex(UserHeaderPattern); + llvm::Regex MatchQuotes = llvm::Regex(IncludeWithQuotesPattern); + if (MatchKernel.match(Filename)) + return IHK_KERNELHEADERS; + else if (MatchNetwork.match(Filename)) + return IHK_NETWORKHEADERS; + else if (MatchArch.match(Filename)) + return IHK_ARCHHEADERS; + else if (MatchQuotes.match(Filename)) + return IHK_INCLUDESWITHQUOTES; + else if (MatchUser.match(Filename)) + return IHK_USERHEADERS; + else if (MatchFileSys.match(Filename)) + return IHK_FILESYSHEADERS; + else if (MatchMachine.match(Filename)) + return IHK_MACHINESHEADERS; + return IHK_INCLUDESWITHQUOTES; +} + +unsigned getNetBSDIncludePriority(std::string Filename) { + CppIncludeHeadersKind CK = getHeadersKind(Filename); + switch (CK) { + case IHK_KERNELHEADERS: + return llvm::StringSwitch<unsigned>(Filename) + .Case("<sys/param.h>", 0) + .Case("<sys/types.h>", 1) + .StartsWith("<sys/", 2) + .StartsWith("<uvm/", 3) + .StartsWith("<dev/", 7) + .Default(1002); + case IHK_NETWORKHEADERS: + return llvm::StringSwitch<unsigned>(Filename) + .StartsWith("<net", 4) + .StartsWith("<protocols", 5) + .Default(1002); + case IHK_FILESYSHEADERS: + return 6; + case IHK_MACHINESHEADERS: + return 8; + case IHK_ARCHHEADERS: + return 9; + case IHK_USERHEADERS: + return llvm::StringSwitch<unsigned>(Filename) + .StartsWith("<path",11) + .Default(10); + case IHK_INCLUDESWITHQUOTES: + return 12; + } + return 100; +} +static void sortNetBSDIncludes( + const FormatStyle &Style, const SmallVectorImpl<IncludeDirective> &Includes, + ArrayRef<tooling::Range> Ranges, StringRef FileName, StringRef Code, + tooling::Replacements &Replaces, unsigned *Cursor) { + unsigned IncludesBeginOffset = Includes.front().Offset; + unsigned IncludesEndOffset = + Includes.back().Offset + Includes.back().Text.size(); + unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset; + if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset)) + return; + SmallVector<unsigned, 16> Indices; + SmallVector<unsigned, 16> Includes_p; + for (unsigned i = 0, e = Includes.size(); i != e; ++i) { + unsigned pl = getNetBSDIncludePriority(Includes[i].Filename); + Includes_p.push_back(pl); + Indices.push_back(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_p[LHSI], Includes[LHSI].Filename) < + std::tie(Includes_p[RHSI], Includes[RHSI].Filename); + }); + + // The index of the include on which the cursor will be put after + // sorting/deduplicating. + unsigned CursorIndex; + // The offset from cursor to the end of line. + unsigned CursorToEOLOffset; + if (Cursor) + std::tie(CursorIndex, CursorToEOLOffset) = + FindCursorIndex(Includes, Indices, *Cursor); + // Deduplicate #includes. + Indices.erase(std::unique(Indices.begin(), Indices.end(), + [&](unsigned LHSI, unsigned RHSI) { + return Includes[LHSI].Text == Includes[RHSI].Text; + }), + Indices.end()); + + int CurrentCategory = Includes.front().Category; + // If the #includes are out of order, we generate a single replacement fixing + // the entire block. Otherwise, no replacement is generated. + // In case Style.IncldueStyle.IncludeBlocks != IBS_Preserve, this check is not + // enough as additional newlines might be added or removed across #include + // blocks. This we handle below by generating the updated #imclude blocks and + // comparing it to the original. + if (Indices.size() == Includes.size() && + std::is_sorted(Indices.begin(), Indices.end()) && + Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Preserve) + return; + + std::string result; + for (unsigned Index : Indices) { + if (!result.empty()) { + result += "\n"; + if ((Style.IncludeStyle.IncludeBlocks == + tooling::IncludeStyle::IBS_Regroup) && + CurrentCategory != Includes[Index].Category) + result += "\n"; + } + result += Includes[Index].Text; + if (Cursor && CursorIndex == Index) + *Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset; + CurrentCategory = Includes[Index].Category; + } + + // If the #includes are out of order, we generate a single replacement fixing + // the entire range of blocks. Otherwise, no replacement is generated. + if (result == Code.substr(IncludesBeginOffset, IncludesBlockSize)) + return; + + auto Err = Replaces.add(tooling::Replacement( + FileName, Includes.front().Offset, IncludesBlockSize, result)); + // FIXME: better error handling. For now, just skip the replacement for the + // release version. + if (Err) { + llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } +} // Sorts and deduplicate a block of includes given by 'Includes' alphabetically // adding the necessary replacement to 'Replaces'. 'Includes' must be in strict // source order. @@ -1774,8 +1956,8 @@ static void sortCppIncludes(const FormatStyle &Style, const SmallVectorImpl<IncludeDirective> &Includes, ArrayRef<tooling::Range> Ranges, StringRef FileName, - StringRef Code, - tooling::Replacements &Replaces, unsigned *Cursor) { + StringRef Code, tooling::Replacements &Replaces, + unsigned *Cursor) { unsigned IncludesBeginOffset = Includes.front().Offset; unsigned IncludesEndOffset = Includes.back().Offset + Includes.back().Text.size(); @@ -1906,8 +2088,12 @@ MainIncludeFound = true; IncludesInBlock.push_back({IncludeName, Line, Prev, Category}); } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) { - sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, - Replaces, Cursor); + if (Style.SortNetBSDIncludes) + sortNetBSDIncludes(Style, IncludesInBlock, Ranges, FileName, Code, + Replaces, Cursor); + else + sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, + Replaces, Cursor); IncludesInBlock.clear(); FirstIncludeBlock = false; } @@ -1918,8 +2104,12 @@ SearchFrom = Pos + 1; } if (!IncludesInBlock.empty()) { - sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, Replaces, - Cursor); + if (Style.SortNetBSDIncludes) + sortNetBSDIncludes(Style, IncludesInBlock, Ranges, FileName, Code, + Replaces, Cursor); + else + sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, Replaces, + Cursor); } return Replaces; } Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1681,6 +1681,9 @@ /// \endcode bool SortIncludes; + /// If ``true``, clang-format will sort ``#includes`` according to NetBSD Style. + bool SortNetBSDIncludes; + /// If ``true``, clang-format will sort using declarations. /// /// The order of using declarations is defined as follows: @@ -1995,6 +1998,7 @@ R.PenaltyBreakTemplateDeclaration && PointerAlignment == R.PointerAlignment && RawStringFormats == R.RawStringFormats && + SortNetBSDIncludes == R.SortNetBSDIncludes && SpaceAfterCStyleCast == R.SpaceAfterCStyleCast && SpaceAfterLogicalNot == R.SpaceAfterLogicalNot && SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword && @@ -2083,6 +2087,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: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -2001,6 +2001,10 @@ #include "b.h" vs. #include "a.h" #include "a.h" #include "b.h" +**SortNetBSDIncludes** (``bool``) + If ``true``, clang-format will sort ``#includes`` according to NetBSD style. + + **SortUsingDeclarations** (``bool``) If ``true``, clang-format will sort using declarations.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits