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= - 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= - Set coding style. 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..bef5924ca74b0 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -131,6 +131,11 @@ static cl::opt 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 + Recursive("r", + cl::desc("Recursively format files in any specified directories"), + cl::cat(ClangFormatCategory)); + static cl::opt Verbose("verbose", cl::desc("If set, shows the list of processed files"), cl::cat(ClangFormatCategory)); @@ -700,6 +705,31 @@ int main(int argc, const char **argv) { errs() << "Clang-formatting " << LineNo << " files\n"; } + if (Recursive) { + SmallVector 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;