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