[clang] [clang-format] Add -r option for recursing into directories (PR #160299)
James Henderson via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 23 06:45:32 PDT 2025
https://github.com/jh7370 created https://github.com/llvm/llvm-project/pull/160299
The option recursively replaces any directories on the command-line with all entries within the specified directories, making it easier to reformat an entire directory tree.
Fixes #62108
>From d03222069e3eba7061dd831e8ddb3df17caa553a Mon Sep 17 00:00:00 2001
From: James Henderson <james.henderson at sony.com>
Date: Tue, 23 Sep 2025 14:40:53 +0100
Subject: [PATCH] [clang-format] Add -r option for recursing into directories
The option recursively replaces any directories on the command-line with
all entries within the specified directories, making it easier to
reformat an entire directory tree.
Fixes #62108
---
clang/docs/ClangFormat.rst | 1 +
clang/docs/ReleaseNotes.rst | 1 +
clang/test/Format/recursive.test | 21 +++++++++++++++++
clang/tools/clang-format/ClangFormat.cpp | 29 ++++++++++++++++++++++++
4 files changed, 52 insertions(+)
create mode 100644 clang/test/Format/recursive.test
diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst
index 92af06e5083d6..cd00bedefa21b 100644
--- a/clang/docs/ClangFormat.rst
+++ b/clang/docs/ClangFormat.rst
@@ -93,6 +93,7 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code.
--output-replacements-xml - Output replacements as XML.
--qualifier-alignment=<string> - If set, overrides the qualifier alignment style
determined by the QualifierAlignment style flag
+ -r - Recursively format files in any specified directories
--sort-includes - If set, overrides the include sorting behavior
determined by the SortIncludes style flag
--style=<string> - Set coding style. <string> can be:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fb429a675476d..e64ef490d292a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -532,6 +532,7 @@ clang-format
literals.
- Add ``Leave`` suboption to ``IndentPPDirectives``.
- Add ``AllowBreakBeforeQtProperty`` option.
+- Add ``-r`` option for recursing into specified directories when formatting.
libclang
--------
diff --git a/clang/test/Format/recursive.test b/clang/test/Format/recursive.test
new file mode 100644
index 0000000000000..f0f3b9e5a3f07
--- /dev/null
+++ b/clang/test/Format/recursive.test
@@ -0,0 +1,21 @@
+RUN: rm -rf %t && mkdir %t
+RUN: split-file %s %t
+
+RUN: clang-format -i -r --verbose %t 2>&1 | FileCheck %s -DDIR=%t -DSEP=%{fs-sep}
+
+CHECK: Formatting [1/4] [[DIR]][[SEP]]1.cpp
+CHECK: Formatting [2/4] [[DIR]][[SEP]]2[[SEP]]3.cpp
+CHECK: Formatting [3/4] [[DIR]][[SEP]]2[[SEP]]4[[SEP]]5.cpp
+CHECK: Formatting [4/4] [[DIR]][[SEP]]2[[SEP]]6.cpp
+
+#--- 1.cpp
+int x;
+
+#--- 2/3.cpp
+int x;
+
+#--- 2/4/5.cpp
+int x;
+
+#--- 2/6.cpp
+int x;
diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp
index 5f6502f7f18a8..8267417e311f0 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -131,6 +131,10 @@ static cl::opt<std::string> Files(
cl::desc("A file containing a list of files to process, one per line."),
cl::value_desc("filename"), cl::init(""), cl::cat(ClangFormatCategory));
+static cl::opt<bool> Recursive("r",
+ cl::desc("Recursively format files in any specified directories"),
+ cl::cat(ClangFormatCategory));
+
static cl::opt<bool>
Verbose("verbose", cl::desc("If set, shows the list of processed files"),
cl::cat(ClangFormatCategory));
@@ -700,6 +704,31 @@ int main(int argc, const char **argv) {
errs() << "Clang-formatting " << LineNo << " files\n";
}
+ if (Recursive) {
+ SmallVector<std::string> ExpandedNames;
+ for (const std::string &Path : FileNames) {
+ if (sys::fs::is_directory(Path)) {
+ std::error_code ErrorCode;
+ for (sys::fs::recursive_directory_iterator I(Path, ErrorCode), E;
+ I != E && !ErrorCode; I.increment(ErrorCode)) {
+ bool Result = false;
+ ErrorCode = sys::fs::is_regular_file(I->path(), Result);
+ // Conservatively assume that any unopenable entries are also regular
+ // files. Later code will emit an error when trying to format them, if
+ // they aren't valid by then.
+ if (ErrorCode || Result)
+ ExpandedNames.push_back(I->path());
+ }
+ } else {
+ ExpandedNames.push_back(std::move(Path));
+ }
+ }
+
+ FileNames.clear();
+ for (const std::string &Name : ExpandedNames)
+ FileNames.push_back(Name);
+ }
+
if (FileNames.empty()) {
if (isIgnored(AssumeFileName))
return 0;
More information about the cfe-commits
mailing list