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

Reply via email to