https://github.com/owenca updated 
https://github.com/llvm/llvm-project/pull/76327

>From 4afd12db61528b40d842a7fbee9af37c2235822c Mon Sep 17 00:00:00 2001
From: Owen Pan <owenpi...@gmail.com>
Date: Sun, 24 Dec 2023 01:18:55 -0800
Subject: [PATCH 1/2] [clang-format] Add .clang-format.ignore for ignoring
 files

Closes #52975.
---
 clang/docs/ClangFormat.rst                | 18 ++++++
 clang/test/Format/clang-format-ignore.cpp | 24 ++++++++
 clang/tools/clang-format/ClangFormat.cpp  | 71 ++++++++++++++++++++++-
 3 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Format/clang-format-ignore.cpp

diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst
index f52f35550d03eb..a0b28f2273991f 100644
--- a/clang/docs/ClangFormat.rst
+++ b/clang/docs/ClangFormat.rst
@@ -131,6 +131,24 @@ An easy way to create the ``.clang-format`` file is:
 
 Available style options are described in :doc:`ClangFormatStyleOptions`.
 
+You can create ``.clang-format-ignore`` files to make ``clang-format`` ignore
+certain files. A ``.clang-format-ignore`` file consists of patterns of file 
path
+names. It has the following format:
+- A blank line is skipped.
+- Leading and trailing spaces of a line are trimmed.
+- A line starting with a hash (``#``) is a comment.
+- A non-comment line is a single pattern.
+- The slash (``/``) is used as the directory separator.
+- A pattern is relative to the directory of the ``.clang-format-ignore`` file
+  (or the root directory if the pattern starts with a slash).
+- Patterns follow the rules specified in POSIX 2.13.1, 2.13.2, and Rule 1 of
+  2.13.3.
+- A pattern is negated if it starts with a bang (``!``).
+To match all files in a directory, use e.g. ``foo/bar/*``. To match all files 
in
+the directory of the ``.clang-format-ignore`` file, use ``*``.
+Multiple ``.clang-format-ignore`` files are supported similar to the
+``.clang-format`` files, with a lower directory level file voiding the higher
+level ones.
 
 Vim Integration
 ===============
diff --git a/clang/test/Format/clang-format-ignore.cpp 
b/clang/test/Format/clang-format-ignore.cpp
new file mode 100644
index 00000000000000..a2210266034d4c
--- /dev/null
+++ b/clang/test/Format/clang-format-ignore.cpp
@@ -0,0 +1,24 @@
+// RUN: mkdir -p %t.dir/level1/level2
+
+// RUN: cd %t.dir
+// RUN: printf "*\nlevel*/*.c*\n*/*2/foo.*\n" > .clang-format-ignore
+// RUN: touch foo.cc
+// RUN: clang-format -verbose .clang-format-ignore foo.cc 2> %t.stderr
+// RUN: not grep "Formatting" %t.stderr
+
+// RUN: cd level1
+// RUN: touch bar.cc baz.c
+// RUN: clang-format -verbose bar.cc baz.c 2> %t.stderr
+// RUN: not grep "Formatting" %t.stderr
+
+// RUN: cd level2
+// RUN: touch foo.c foo.js
+// RUN: clang-format -verbose foo.c foo.js 2> %t.stderr
+// RUN: not grep "Formatting" %t.stderr
+// RUN: printf "*.js\n" > .clang-format-ignore
+// RUN: clang-format -verbose foo.c foo.js 2> %t.stderr
+// RUN: grep -E "Formatting (.*)foo.c(.*)" %t.stderr
+// RUN: not grep -E "Formatting (.*)foo.js(.*)" %t.stderr
+
+// RUN: cd ../../..
+// RUN: rm -rf %t.dir
diff --git a/clang/tools/clang-format/ClangFormat.cpp 
b/clang/tools/clang-format/ClangFormat.cpp
index d2e3d8d43aef21..be78f8cbebf5e1 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -12,6 +12,7 @@
 ///
 
//===----------------------------------------------------------------------===//
 
+#include "../../lib/Format/MatchFilePath.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/FileManager.h"
@@ -570,6 +571,71 @@ static int dumpConfig(bool IsSTDIN) {
   return 0;
 }
 
+// Check whether `FilePath` is ignored according to the nearest
+// .clang-format-ignore file based on the rules below:
+// - A blank line is skipped.
+// - Leading and trailing spaces of a line are trimmed.
+// - A line starting with a hash (`#`) is a comment.
+// - A non-comment line is a single pattern.
+// - The slash (`/`) is used as the directory separator.
+// - A pattern is relative to the directory of the .clang-format-ignore file 
(or
+//   the root directory if the pattern starts with a slash).
+// - A pattern is negated if it starts with a bang (`!`).
+static bool isIgnored(const StringRef FilePath) {
+  if (!llvm::sys::fs::is_regular_file(FilePath))
+    return false;
+
+  using namespace llvm::sys::path;
+  SmallString<128> Path, AbsPath{convert_to_slash(FilePath)};
+
+  llvm::vfs::getRealFileSystem()->makeAbsolute(AbsPath);
+  remove_dots(AbsPath, /*remove_dot_dot=*/true);
+
+  StringRef IgnoreDir{AbsPath};
+  do {
+    IgnoreDir = parent_path(IgnoreDir);
+    if (IgnoreDir.empty())
+      return false;
+
+    Path = IgnoreDir;
+    append(Path, ".clang-format-ignore");
+  } while (!llvm::sys::fs::is_regular_file(Path));
+
+  std::ifstream IgnoreFile{Path.c_str()};
+  if (!IgnoreFile.good())
+    return false;
+
+  bool HasMatch = false;
+  for (std::string Pattern; std::getline(IgnoreFile, Pattern);) {
+    Pattern = StringRef(Pattern).trim();
+    if (Pattern.empty() || Pattern[0] == '#')
+      continue;
+
+    const bool IsNegated = Pattern[0] == '!';
+    if (IsNegated)
+      Pattern.erase(0, 1);
+
+    if (Pattern.empty())
+      continue;
+
+    Pattern = StringRef(Pattern).ltrim();
+    if (Pattern[0] != '/') {
+      Path = IgnoreDir;
+      append(Path, Pattern);
+      remove_dots(Path, /*remove_dot_dot=*/true);
+      Pattern = Path.str();
+    }
+
+    if (clang::format::matchFilePath(Pattern, AbsPath.str()) == !IsNegated) {
+      HasMatch = true;
+      break;
+    }
+  }
+
+  IgnoreFile.close();
+  return HasMatch;
+}
+
 int main(int argc, const char **argv) {
   llvm::InitLLVM X(argc, argv);
 
@@ -618,11 +684,14 @@ int main(int argc, const char **argv) {
   unsigned FileNo = 1;
   bool Error = false;
   for (const auto &FileName : FileNames) {
+    const bool IsSTDIN = FileName == "-";
+    if (!IsSTDIN && isIgnored(FileName))
+      continue;
     if (Verbose) {
       errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
              << FileName << "\n";
     }
-    Error |= clang::format::format(FileName, FileName == "-");
+    Error |= clang::format::format(FileName, IsSTDIN);
   }
   return Error ? 1 : 0;
 }

>From 0abdba2a457be700921e903f66b5a3d7ca54c55f Mon Sep 17 00:00:00 2001
From: Owen Pan <owenpi...@gmail.com>
Date: Sun, 24 Dec 2023 01:41:22 -0800
Subject: [PATCH 2/2] Update clang/docs/ClangFormat.rst

---
 clang/docs/ClangFormat.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst
index a0b28f2273991f..822839c6842521 100644
--- a/clang/docs/ClangFormat.rst
+++ b/clang/docs/ClangFormat.rst
@@ -140,9 +140,9 @@ names. It has the following format:
 - A non-comment line is a single pattern.
 - The slash (``/``) is used as the directory separator.
 - A pattern is relative to the directory of the ``.clang-format-ignore`` file
-  (or the root directory if the pattern starts with a slash).
+(or the root directory if the pattern starts with a slash).
 - Patterns follow the rules specified in POSIX 2.13.1, 2.13.2, and Rule 1 of
-  2.13.3.
+2.13.3.
 - A pattern is negated if it starts with a bang (``!``).
 To match all files in a directory, use e.g. ``foo/bar/*``. To match all files 
in
 the directory of the ``.clang-format-ignore`` file, use ``*``.

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to