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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits