https://github.com/dzbarsky updated 
https://github.com/llvm/llvm-project/pull/201730

>From cfcbe11ee07f58a5498f1bf0af9f649570cebbee Mon Sep 17 00:00:00 2001
From: David Zbarsky <[email protected]>
Date: Thu, 4 Jun 2026 21:47:06 -0400
Subject: [PATCH] Convert clang-format to Opt and add multicall support

---
 clang/docs/ClangFormat.rst                    | 172 +++----
 clang/tools/clang-format/CMakeLists.txt       |  13 +-
 clang/tools/clang-format/ClangFormat.cpp      | 432 +++++++++---------
 clang/tools/clang-format/Opts.td              | 154 +++++++
 .../llvm-project-overlay/clang/BUILD.bazel    |  22 +-
 .../llvm-project-overlay/llvm/driver.bzl      |   1 +
 6 files changed, 498 insertions(+), 296 deletions(-)
 create mode 100644 clang/tools/clang-format/Opts.td

diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst
index 26490f9c15bb8..e7fac3e2eaad6 100644
--- a/clang/docs/ClangFormat.rst
+++ b/clang/docs/ClangFormat.rst
@@ -29,92 +29,92 @@ to format 
C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code.
   USAGE: clang-format [options] [@<file>] [<file> ...]
 
   OPTIONS:
-
-  Clang-format options:
-
-    --Werror                       - If set, changes formatting warnings to 
errors
-    --Wno-error=<value>            - If set, don't error out on the specified 
warning type.
-      =unknown                     -   If set, unknown format options are only 
warned about.
-                                       This can be used to enable formatting, 
even if the
-                                       configuration contains unknown (newer) 
options.
-                                       Use with caution, as this might lead to 
dramatically
-                                       differing format depending on an option 
being
-                                       supported or not.
-    --assume-filename=<string>     - Set filename used to determine the 
language and to find
-                                     .clang-format file.
-                                     Only used when reading from stdin.
-                                     If this is not passed, the .clang-format 
file is searched
-                                     relative to the current working directory 
when reading stdin.
-                                     Unrecognized filenames are treated as C++.
-                                     supported:
-                                       CSharp: .cs
-                                       Java: .java
-                                       JavaScript: .js .mjs .cjs .ts
-                                       JSON: .json .ipynb
-                                       Objective-C: .m .mm
-                                       Proto: .proto .protodevel
-                                       TableGen: .td
-                                       TextProto: .txtpb .textpb .pb.txt 
.textproto .asciipb
-                                       Verilog: .sv .svh .v .vh
-    --cursor=<uint>                - The position of the cursor when invoking
-                                     clang-format from an editor integration
-    --dry-run                      - If set, do not actually make the 
formatting changes
-    --dump-config                  - Dump configuration options to stdout and 
exit.
-                                     Can be used with -style option.
-    --fail-on-incomplete-format    - If set, fail with exit code 1 on 
incomplete format.
-    --fallback-style=<string>      - The name of the predefined style used as a
-                                     fallback in case clang-format is invoked 
with
-                                     -style=file, but can not find the 
.clang-format
-                                     file to use. Defaults to 'LLVM'.
-                                     Use -fallback-style=none to skip 
formatting.
-    --ferror-limit=<uint>          - Set the maximum number of clang-format 
errors to emit
-                                     before stopping (0 = no limit).
-                                     Used only with --dry-run or -n
-    --files=<filename>             - A file containing a list of files to 
process, one per line.
-    -i                             - Inplace edit <file>s, if specified.
-    --length=<uint>                - Format a range of this length (in bytes).
-                                     Multiple ranges can be formatted by 
specifying
-                                     several -offset and -length pairs.
-                                     When only a single -offset is specified 
without
-                                     -length, clang-format will format up to 
the end
-                                     of the file.
-                                     Can only be used with one input file.
-    --lines=<string>               - <start line>:<end line> - format a range 
of
-                                     lines (both 1-based).
-                                     Multiple ranges can be formatted by 
specifying
-                                     several -lines arguments.
-                                     Can't be used with -offset and -length.
-                                     Can only be used with one input file.
-    -n                             - Alias for --dry-run
-    --offset=<uint>                - Format a range starting at this byte 
offset.
-                                     Multiple ranges can be formatted by 
specifying
-                                     several -offset and -length pairs.
-                                     Can only be used with one input file.
-    --output-replacements-xml      - Output replacements as XML.
-    --qualifier-alignment=<string> - If set, overrides the qualifier alignment 
style
-                                     determined by the QualifierAlignment 
style flag
-    --sort-includes                - If set, overrides the include sorting 
behavior
-                                     determined by the SortIncludes style flag
-    --style=<string>               - Set coding style. <string> can be:
-                                     1. A preset: LLVM, GNU, Google, Chromium, 
Microsoft,
-                                        Mozilla, WebKit.
-                                     2. 'file' to load style configuration 
from a
-                                        .clang-format file in one of the 
parent directories
-                                        of the source file (for stdin, see 
--assume-filename).
-                                        If no .clang-format file is found, 
falls back to
-                                        --fallback-style.
-                                        --style=file is the default.
-                                     3. 'file:<format_file_path>' to 
explicitly specify
-                                        the configuration file.
-                                     4. "{key: value, ...}" to set specific 
parameters, e.g.:
-                                        --style="{BasedOnStyle: llvm, 
IndentWidth: 8}"
-    --verbose                      - If set, shows the list of processed files
-
-  Generic Options:
-
-    --help                         - Display available options (--help-hidden 
for more)
-    --help-list                    - Display list of available options 
(--help-list-hidden for more)
-    --version                      - Display the version of this program
+    -assume-filename=<string>
+                         Set filename used to determine the language and to 
find
+                         .clang-format file.
+                         Only used when reading from stdin.
+                         If this is not passed, the .clang-format file is 
searched
+                         relative to the current working directory when 
reading stdin.
+                         Unrecognized filenames are treated as C++.
+                         supported:
+                           CSharp: .cs
+                           Java: .java
+                           JavaScript: .js .mjs .cjs .ts
+                           JSON: .json .ipynb
+                           Objective-C: .m .mm
+                           Proto: .proto .protodevel
+                           TableGen: .td
+                           TextProto: .txtpb .textpb .pb.txt .textproto 
.asciipb
+                           Verilog: .sv .svh .v .vh
+    -cursor=<uint>       The position of the cursor when invoking
+                         clang-format from an editor integration
+    -dry-run             If set, do not actually make the formatting changes
+    -dump-config         Dump configuration options to stdout and exit.
+                         Can be used with -style option.
+    -fail-on-incomplete-format
+                         If set, fail with exit code 1 on incomplete format.
+    -fallback-style=<string>
+                         The name of the predefined style used as a
+                         fallback in case clang-format is invoked with
+                         -style=file, but can not find the .clang-format
+                         file to use. Defaults to 'LLVM'.
+                         Use -fallback-style=none to skip formatting.
+    -ferror-limit=<uint> Set the maximum number of clang-format errors to emit
+                         before stopping (0 = no limit).
+                         Used only with --dry-run or -n
+    -files=<filename>    A file containing a list of files to process, one per 
line.
+    -help-hidden         Display all available options, including hidden 
options
+    -help                Display available options
+    -i                   Inplace edit <file>s, if specified.
+    -length=<uint>       Format a range of this length (in bytes).
+                         Multiple ranges can be formatted by specifying
+                         several -offset and -length pairs.
+                         When only a single -offset is specified without
+                         -length, clang-format will format up to the end
+                         of the file.
+                         Can only be used with one input file.
+    -lines=<start line>:<end line>
+                         Format a range of lines (both 1-based).
+                         Multiple ranges can be formatted by specifying
+                         several -lines arguments.
+                         Can't be used with -offset and -length.
+                         Can only be used with one input file.
+    -n                   Alias for --dry-run
+    -offset=<uint>       Format a range starting at this byte offset.
+                         Multiple ranges can be formatted by specifying
+                         several -offset and -length pairs.
+                         Can only be used with one input file.
+    -output-replacements-xml
+                         Output replacements as XML.
+    -qualifier-alignment=<string>
+                         If set, overrides the qualifier alignment style
+                         determined by the QualifierAlignment style flag
+    -sort-includes       If set, overrides the include sorting behavior
+                         determined by the SortIncludes style flag
+    -style=<string>      Set coding style. <string> can be:
+                         1. A preset: LLVM, GNU, Google, Chromium, Microsoft,
+                            Mozilla, WebKit.
+                         2. 'file' to load style configuration from a
+                            .clang-format file in one of the parent directories
+                            of the source file (for stdin, see 
--assume-filename).
+                            If no .clang-format file is found, falls back to
+                            --fallback-style.
+                            --style=file is the default.
+                         3. 'file:<format_file_path>' to explicitly specify
+                            the configuration file.
+                         4. "{key: value, ...}" to set specific parameters, 
e.g.:
+                            --style="{BasedOnStyle: llvm, IndentWidth: 8}"
+    -verbose             If set, shows the list of processed files
+    -version             Display the version of this program
+    -Werror              If set, changes formatting warnings to errors
+    -Wno-error=<warning> If set, don't error out on the specified warning type.
+                         Supported warnings:
+                           unknown - unknown format options are only warned 
about.
+                         This can be used to enable formatting, even if the
+                         configuration contains unknown (newer) options.
+                         Use with caution, as this might lead to dramatically
+                         differing format depending on an option being
+                         supported or not.
 
 
 .. END_FORMAT_HELP
diff --git a/clang/tools/clang-format/CMakeLists.txt 
b/clang/tools/clang-format/CMakeLists.txt
index 1c61a3c8fb803..5a1e53d3aa99b 100644
--- a/clang/tools/clang-format/CMakeLists.txt
+++ b/clang/tools/clang-format/CMakeLists.txt
@@ -1,7 +1,18 @@
-set(LLVM_LINK_COMPONENTS support)
+set(LLVM_LINK_COMPONENTS
+  Option
+  Support
+  )
+
+set(LLVM_TARGET_DEFINITIONS Opts.td)
+tablegen(LLVM Opts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ClangFormatOptsTableGen)
 
 add_clang_tool(clang-format
   ClangFormat.cpp
+
+  DEPENDS
+  ClangFormatOptsTableGen
+  GENERATE_DRIVER
   )
 
 set(CLANG_FORMAT_LIB_DEPS
diff --git a/clang/tools/clang-format/ClangFormat.cpp 
b/clang/tools/clang-format/ClangFormat.cpp
index 37d0eb83414f4..f4bf01fbc4e39 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -21,198 +21,80 @@
 #include "clang/Format/Format.h"
 #include "clang/Rewrite/Core/Rewriter.h"
 #include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/CommandLine.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Allocator.h"
 #include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/Process.h"
+#include "llvm/Support/LLVMDriver.h"
+#include "llvm/Support/StringSaver.h"
 #include <fstream>
+#include <optional>
+#include <string>
+#include <vector>
 
 using namespace llvm;
 using clang::tooling::Replacements;
 
-static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
-
-// Mark all our options with this category, everything else (except for 
-version
-// and -help) will be hidden.
-static cl::OptionCategory ClangFormatCategory("Clang-format options");
-
-static cl::list<unsigned>
-    Offsets("offset",
-            cl::desc("Format a range starting at this byte offset.\n"
-                     "Multiple ranges can be formatted by specifying\n"
-                     "several -offset and -length pairs.\n"
-                     "Can only be used with one input file."),
-            cl::cat(ClangFormatCategory));
-static cl::list<unsigned>
-    Lengths("length",
-            cl::desc("Format a range of this length (in bytes).\n"
-                     "Multiple ranges can be formatted by specifying\n"
-                     "several -offset and -length pairs.\n"
-                     "When only a single -offset is specified without\n"
-                     "-length, clang-format will format up to the end\n"
-                     "of the file.\n"
-                     "Can only be used with one input file."),
-            cl::cat(ClangFormatCategory));
-static cl::list<std::string>
-    LineRanges("lines",
-               cl::desc("<start line>:<end line> - format a range of\n"
-                        "lines (both 1-based).\n"
-                        "Multiple ranges can be formatted by specifying\n"
-                        "several -lines arguments.\n"
-                        "Can't be used with -offset and -length.\n"
-                        "Can only be used with one input file."),
-               cl::cat(ClangFormatCategory));
-static cl::opt<std::string>
-    Style("style", cl::desc(clang::format::StyleOptionHelpDescription),
-          cl::init(clang::format::DefaultFormatStyle),
-          cl::cat(ClangFormatCategory));
-static cl::opt<std::string>
-    FallbackStyle("fallback-style",
-                  cl::desc("The name of the predefined style used as a\n"
-                           "fallback in case clang-format is invoked with\n"
-                           "-style=file, but can not find the .clang-format\n"
-                           "file to use. Defaults to 'LLVM'.\n"
-                           "Use -fallback-style=none to skip formatting."),
-                  cl::init(clang::format::DefaultFallbackStyle),
-                  cl::cat(ClangFormatCategory));
-
-static cl::opt<std::string> AssumeFileName(
-    "assume-filename",
-    cl::desc("Set filename used to determine the language and to find\n"
-             ".clang-format file.\n"
-             "Only used when reading from stdin.\n"
-             "If this is not passed, the .clang-format file is searched\n"
-             "relative to the current working directory when reading stdin.\n"
-             "Unrecognized filenames are treated as C++.\n"
-             "supported:\n"
-             "  CSharp: .cs\n"
-             "  Java: .java\n"
-             "  JavaScript: .js .mjs .cjs .ts\n"
-             "  JSON: .json .ipynb\n"
-             "  Objective-C: .m .mm\n"
-             "  Proto: .proto .protodevel\n"
-             "  TableGen: .td\n"
-             "  TextProto: .txtpb .textpb .pb.txt .textproto .asciipb\n"
-             "  Verilog: .sv .svh .v .vh"),
-    cl::init("<stdin>"), cl::cat(ClangFormatCategory));
-
-static cl::opt<bool> Inplace("i",
-                             cl::desc("Inplace edit <file>s, if specified."),
-                             cl::cat(ClangFormatCategory));
-
-static cl::opt<bool> OutputXML("output-replacements-xml",
-                               cl::desc("Output replacements as XML."),
-                               cl::cat(ClangFormatCategory));
-static cl::opt<bool>
-    DumpConfig("dump-config",
-               cl::desc("Dump configuration options to stdout and exit.\n"
-                        "Can be used with -style option."),
-               cl::cat(ClangFormatCategory));
-static cl::opt<unsigned>
-    Cursor("cursor",
-           cl::desc("The position of the cursor when invoking\n"
-                    "clang-format from an editor integration"),
-           cl::init(0), cl::cat(ClangFormatCategory));
-
-static cl::opt<bool>
-    SortIncludes("sort-includes",
-                 cl::desc("If set, overrides the include sorting behavior\n"
-                          "determined by the SortIncludes style flag"),
-                 cl::cat(ClangFormatCategory));
-
-static cl::opt<std::string> QualifierAlignment(
-    "qualifier-alignment",
-    cl::desc("If set, overrides the qualifier alignment style\n"
-             "determined by the QualifierAlignment style flag"),
-    cl::init(""), cl::cat(ClangFormatCategory));
-
-static cl::opt<std::string> Files(
-    "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>
-    Verbose("verbose", cl::desc("If set, shows the list of processed files"),
-            cl::cat(ClangFormatCategory));
-
-// Use --dry-run to match other LLVM tools when you mean do it but don't
-// actually do it
-static cl::opt<bool>
-    DryRun("dry-run",
-           cl::desc("If set, do not actually make the formatting changes"),
-           cl::cat(ClangFormatCategory));
-
-// Use -n as a common command as an alias for --dry-run. (git and make use -n)
-static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"),
-                             cl::cat(ClangFormatCategory), 
cl::aliasopt(DryRun),
-                             cl::NotHidden);
-
-// Emulate being able to turn on/off the warning.
-static cl::opt<bool>
-    WarnFormat("Wclang-format-violations",
-               cl::desc("Warnings about individual formatting changes needed. "
-                        "Used only with --dry-run or -n"),
-               cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
-
-static cl::opt<bool>
-    NoWarnFormat("Wno-clang-format-violations",
-                 cl::desc("Do not warn about individual formatting changes "
-                          "needed. Used only with --dry-run or -n"),
-                 cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
-
-static cl::opt<unsigned> ErrorLimit(
-    "ferror-limit",
-    cl::desc("Set the maximum number of clang-format errors to emit\n"
-             "before stopping (0 = no limit).\n"
-             "Used only with --dry-run or -n"),
-    cl::init(0), cl::cat(ClangFormatCategory));
-
-static cl::opt<bool>
-    WarningsAsErrors("Werror",
-                     cl::desc("If set, changes formatting warnings to errors"),
-                     cl::cat(ClangFormatCategory));
-
 namespace {
-enum class WNoError { Unknown };
-}
+enum ID {
+  OPT_INVALID = 0,
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
+#include "Opts.inc"
+#undef OPTION
+};
+
+#define OPTTABLE_STR_TABLE_CODE
+#include "Opts.inc"
+#undef OPTTABLE_STR_TABLE_CODE
+
+#define OPTTABLE_PREFIXES_TABLE_CODE
+#include "Opts.inc"
+#undef OPTTABLE_PREFIXES_TABLE_CODE
+
+using namespace llvm::opt;
+static constexpr opt::OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#include "Opts.inc"
+#undef OPTION
+};
 
-static cl::bits<WNoError> WNoErrorList(
-    "Wno-error",
-    cl::desc("If set, don't error out on the specified warning type."),
-    cl::values(
-        clEnumValN(WNoError::Unknown, "unknown",
-                   "If set, unknown format options are only warned about.\n"
-                   "This can be used to enable formatting, even if the\n"
-                   "configuration contains unknown (newer) options.\n"
-                   "Use with caution, as this might lead to dramatically\n"
-                   "differing format depending on an option being\n"
-                   "supported or not.")),
-    cl::cat(ClangFormatCategory));
-
-static cl::opt<bool>
-    ShowColors("fcolor-diagnostics",
-               cl::desc("If set, and on a color-capable terminal controls "
-                        "whether or not to print diagnostics in color"),
-               cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
-
-static cl::opt<bool>
-    NoShowColors("fno-color-diagnostics",
-                 cl::desc("If set, and on a color-capable terminal controls "
-                          "whether or not to print diagnostics in color"),
-                 cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
-
-static cl::list<std::string> FileNames(cl::Positional,
-                                       cl::desc("[@<file>] [<file> ...]"),
-                                       cl::cat(ClangFormatCategory));
-
-static cl::opt<bool> FailOnIncompleteFormat(
-    "fail-on-incomplete-format",
-    cl::desc("If set, fail with exit code 1 on incomplete format."),
-    cl::init(false), cl::cat(ClangFormatCategory));
-
-static cl::opt<bool> ListIgnored("list-ignored",
-                                 cl::desc("List ignored files."),
-                                 cl::cat(ClangFormatCategory), cl::Hidden);
+class ClangFormatOptTable : public opt::GenericOptTable {
+public:
+  ClangFormatOptTable()
+      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
+    setDashDashParsing(true);
+  }
+};
+
+static std::vector<unsigned> Offsets;
+static std::vector<unsigned> Lengths;
+static std::vector<std::string> LineRanges;
+static std::string Style;
+static std::string FallbackStyle;
+static std::string AssumeFileName;
+static bool Inplace;
+static bool OutputXML;
+static bool DumpConfig;
+static unsigned Cursor;
+static bool CursorSpecified;
+static bool SortIncludes;
+static bool SortIncludesSpecified;
+static std::string QualifierAlignment;
+static std::string Files;
+static bool Verbose;
+static bool DryRun;
+static bool WarnFormat;
+static bool NoWarnFormat;
+static unsigned ErrorLimit;
+static bool WarningsAsErrors;
+static bool WNoErrorUnknown;
+static bool ShowColors;
+static bool NoShowColors;
+static std::vector<std::string> FileNames;
+static bool FailOnIncompleteFormat;
+static bool ListIgnored;
+} // namespace
 
 namespace clang {
 namespace format {
@@ -370,7 +252,6 @@ static bool emitReplacementWarnings(const Replacements 
&Replaces,
 static void outputXML(const Replacements &Replaces,
                       const Replacements &FormatChanges,
                       const FormattingAttemptStatus &Status,
-                      const cl::opt<unsigned> &Cursor,
                       unsigned CursorPosition) {
   outs() << "<?xml version='1.0'?>\n<replacements "
             "xml:space='preserve' incomplete_format='"
@@ -378,7 +259,7 @@ static void outputXML(const Replacements &Replaces,
   if (!Status.FormatComplete)
     outs() << " line='" << Status.Line << "'";
   outs() << ">\n";
-  if (Cursor.getNumOccurrences() != 0) {
+  if (CursorSpecified) {
     outs() << "<cursor>" << 
FormatChanges.getShiftedCodePosition(CursorPosition)
            << "</cursor>\n";
   }
@@ -444,7 +325,7 @@ static bool format(StringRef FileName, bool 
ErrorOnIncompleteFormat = false) {
 
   Expected<FormatStyle> FormatStyle =
       getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
-               nullptr, WNoErrorList.isSet(WNoError::Unknown));
+               nullptr, WNoErrorUnknown);
   if (!FormatStyle) {
     llvm::errs() << toString(FormatStyle.takeError()) << "\n";
     return true;
@@ -471,7 +352,7 @@ static bool format(StringRef FileName, bool 
ErrorOnIncompleteFormat = false) {
     FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
   }
 
-  if (SortIncludes.getNumOccurrences() != 0) {
+  if (SortIncludesSpecified) {
     FormatStyle->SortIncludes = {};
     if (SortIncludes)
       FormatStyle->SortIncludes.Enabled = true;
@@ -507,7 +388,7 @@ static bool format(StringRef FileName, bool 
ErrorOnIncompleteFormat = false) {
            emitReplacementWarnings(Replaces, AssumedFileName, std::move(Code));
   }
   if (OutputXML) {
-    outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition);
+    outputXML(Replaces, FormatChanges, Status, CursorPosition);
   } else {
     auto InMemoryFileSystem =
         makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
@@ -526,7 +407,7 @@ static bool format(StringRef FileName, bool 
ErrorOnIncompleteFormat = false) {
       if (Rewrite.overwriteChangedFiles())
         return true;
     } else {
-      if (Cursor.getNumOccurrences() != 0) {
+      if (CursorSpecified) {
         outs() << "{ \"Cursor\": "
                << FormatChanges.getShiftedCodePosition(CursorPosition)
                << ", \"IncompleteFormat\": "
@@ -548,6 +429,138 @@ static void PrintVersion(raw_ostream &OS) {
   OS << clang::getClangToolFullVersion("clang-format") << '\n';
 }
 
+static bool parseUnsignedArgs(const opt::InputArgList &Args, OptSpecifier ID,
+                              std::vector<unsigned> &Values) {
+  for (const opt::Arg *A : Args.filtered(ID)) {
+    unsigned Value;
+    if (!StringRef(A->getValue()).getAsInteger(0, Value)) {
+      Values.push_back(Value);
+      continue;
+    }
+    errs() << "clang-format: invalid value '" << A->getValue()
+           << "' for option '" << A->getSpelling() << "'\n";
+    return false;
+  }
+  return true;
+}
+
+static bool parseBoolArg(const opt::Arg *A, unsigned ValueID, bool &Value) {
+  if (!A->getOption().matches(ValueID)) {
+    Value = true;
+    return true;
+  }
+  std::optional<bool> Parsed = StringSwitch<std::optional<bool>>(A->getValue())
+                                   .CaseLower("true", true)
+                                   .Case("1", true)
+                                   .CaseLower("false", false)
+                                   .Case("0", false)
+                                   .Default(std::nullopt);
+  if (Parsed) {
+    Value = *Parsed;
+    return true;
+  }
+  errs() << "clang-format: invalid value '" << A->getValue() << "' for option 
'"
+         << A->getSpelling() << "'\n";
+  return false;
+}
+
+static bool parseBoolArg(const opt::InputArgList &Args, unsigned FlagID,
+                         unsigned ValueID, bool Default, bool &Value,
+                         bool *Specified = nullptr) {
+  const opt::Arg *A = Args.getLastArg(FlagID, ValueID);
+  if (Specified)
+    *Specified = A != nullptr;
+  if (!A) {
+    Value = Default;
+    return true;
+  }
+  return parseBoolArg(A, ValueID, Value);
+}
+
+static bool parseArgs(int argc, char **argv, StringSaver &Saver,
+                      ClangFormatOptTable &Tbl, opt::InputArgList &Args) {
+  bool HasError = false;
+  Args = Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
+    errs() << "clang-format: " << Msg << '\n';
+    HasError = true;
+  });
+  if (HasError)
+    return false;
+
+  Offsets.clear();
+  Lengths.clear();
+  LineRanges = Args.getAllArgValues(OPT_lines_EQ);
+  Style = Args.getLastArgValue(OPT_style_EQ, 
clang::format::DefaultFormatStyle);
+  FallbackStyle = Args.getLastArgValue(OPT_fallback_style_EQ,
+                                       clang::format::DefaultFallbackStyle);
+  AssumeFileName = Args.getLastArgValue(OPT_assume_filename_EQ, "<stdin>");
+  Cursor = 0;
+  CursorSpecified = Args.hasArg(OPT_cursor_EQ);
+  QualifierAlignment = Args.getLastArgValue(OPT_qualifier_alignment_EQ);
+  Files = Args.getLastArgValue(OPT_files_EQ);
+  ErrorLimit = 0;
+  WNoErrorUnknown = false;
+  FileNames = Args.getAllArgValues(OPT_INPUT);
+
+  if (!parseBoolArg(Args, OPT_i, OPT_i_EQ, false, Inplace) ||
+      !parseBoolArg(Args, OPT_output_replacements_xml,
+                    OPT_output_replacements_xml_EQ, false, OutputXML) ||
+      !parseBoolArg(Args, OPT_dump_config, OPT_dump_config_EQ, false,
+                    DumpConfig) ||
+      !parseBoolArg(Args, OPT_sort_includes, OPT_sort_includes_EQ, false,
+                    SortIncludes, &SortIncludesSpecified) ||
+      !parseBoolArg(Args, OPT_verbose, OPT_verbose_EQ, false, Verbose) ||
+      !parseBoolArg(Args, OPT_dry_run, OPT_dry_run_EQ, false, DryRun) ||
+      !parseBoolArg(Args, OPT_Wclang_format_violations,
+                    OPT_Wclang_format_violations_EQ, true, WarnFormat) ||
+      !parseBoolArg(Args, OPT_Wno_clang_format_violations,
+                    OPT_Wno_clang_format_violations_EQ, false, NoWarnFormat) ||
+      !parseBoolArg(Args, OPT_Werror, OPT_Werror_EQ, false, WarningsAsErrors) 
||
+      !parseBoolArg(Args, OPT_fcolor_diagnostics, OPT_fcolor_diagnostics_EQ,
+                    true, ShowColors) ||
+      !parseBoolArg(Args, OPT_fno_color_diagnostics,
+                    OPT_fno_color_diagnostics_EQ, false, NoShowColors) ||
+      !parseBoolArg(Args, OPT_fail_on_incomplete_format,
+                    OPT_fail_on_incomplete_format_EQ, false,
+                    FailOnIncompleteFormat) ||
+      !parseBoolArg(Args, OPT_list_ignored, OPT_list_ignored_EQ, false,
+                    ListIgnored)) {
+    return false;
+  }
+
+  if (!parseUnsignedArgs(Args, OPT_offset_EQ, Offsets) ||
+      !parseUnsignedArgs(Args, OPT_length_EQ, Lengths)) {
+    return false;
+  }
+
+  if (const opt::Arg *A = Args.getLastArg(OPT_cursor_EQ)) {
+    if (StringRef(A->getValue()).getAsInteger(0, Cursor)) {
+      errs() << "clang-format: invalid value '" << A->getValue()
+             << "' for option '" << A->getSpelling() << "'\n";
+      return false;
+    }
+  }
+
+  if (const opt::Arg *A = Args.getLastArg(OPT_ferror_limit_EQ)) {
+    if (StringRef(A->getValue()).getAsInteger(0, ErrorLimit)) {
+      errs() << "clang-format: invalid value '" << A->getValue()
+             << "' for option '" << A->getSpelling() << "'\n";
+      return false;
+    }
+  }
+
+  for (StringRef Warning : Args.getAllArgValues(OPT_Wno_error_EQ)) {
+    if (Warning == "unknown") {
+      WNoErrorUnknown = true;
+      continue;
+    }
+    errs() << "clang-format: invalid value '" << Warning
+           << "' for option '-Wno-error'\n";
+    return false;
+  }
+  return true;
+}
+
 // Dump the configuration.
 static int dumpConfig() {
   std::unique_ptr<llvm::MemoryBuffer> Code;
@@ -664,24 +677,31 @@ static bool isIgnored(StringRef FilePath) {
   return false;
 }
 
-int main(int argc, const char **argv) {
-  InitLLVM X(argc, argv);
-
-  cl::HideUnrelatedOptions(ClangFormatCategory);
+int clang_format_main(int argc, char **argv, const llvm::ToolContext &) {
+  BumpPtrAllocator Alloc;
+  StringSaver Saver(Alloc);
+  ClangFormatOptTable Tbl;
+  opt::InputArgList Args;
+  if (!parseArgs(argc, argv, Saver, Tbl, Args))
+    return 1;
 
-  cl::SetVersionPrinter(PrintVersion);
-  cl::ParseCommandLineOptions(
-      argc, argv,
-      "A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# "
-      "code.\n\n"
-      "If no arguments are specified, it formats the code from standard 
input\n"
-      "and writes the result to the standard output.\n"
-      "If <file>s are given, it reformats the files. If -i is specified\n"
-      "together with <file>s, the files are edited in-place. Otherwise, the\n"
-      "result is written to the standard output.\n");
+  if (Args.hasArg(OPT_help, OPT_help_hidden)) {
+    Tbl.printHelp(
+        outs(), "clang-format [options] [@<file>] [<file> ...]",
+        "A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# "
+        "code.\n\n"
+        "If no arguments are specified, it formats the code from standard "
+        "input\n"
+        "and writes the result to the standard output.\n"
+        "If <file>s are given, it reformats the files. If -i is specified\n"
+        "together with <file>s, the files are edited in-place. Otherwise, 
the\n"
+        "result is written to the standard output.",
+        Args.hasArg(OPT_help_hidden));
+    return 0;
+  }
 
-  if (Help) {
-    cl::PrintHelpMessage();
+  if (Args.hasArg(OPT_version)) {
+    PrintVersion(outs());
     return 0;
   }
 
diff --git a/clang/tools/clang-format/Opts.td b/clang/tools/clang-format/Opts.td
new file mode 100644
index 0000000000000..48f01ece0b51b
--- /dev/null
+++ b/clang/tools/clang-format/Opts.td
@@ -0,0 +1,154 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name, string help>
+    : Flag<["-", "--"], name>, HelpText<help>;
+
+multiclass B<string name, string help> {
+  def NAME : F<name, help>;
+  def NAME #_EQ : Joined<["-", "--"], name #"=">,
+                   MetaVarName<"<true|false>">,
+                   Flags<[HelpHidden]>;
+}
+
+multiclass BH<string name, string help> {
+  def NAME : F<name, help>, Flags<[HelpHidden]>;
+  def NAME #_EQ : Joined<["-", "--"], name #"=">,
+                   MetaVarName<"<true|false>">,
+                   Flags<[HelpHidden]>;
+}
+
+multiclass Eq<string name, string metavar, string help> {
+  def NAME #_EQ : Joined<["-", "--"], name #"=">,
+                  HelpText<help>, MetaVarName<metavar>;
+  def : Separate<["-", "--"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
+}
+
+def help : F<"help", "Display available options">;
+def help_hidden : F<"help-hidden",
+                    "Display all available options, including hidden options">;
+def version : F<"version", "Display the version of this program">;
+def h : F<"h", "Alias for --help">, Alias<help>, Flags<[HelpHidden]>;
+
+defm offset : Eq<"offset", "<uint>",
+                 "Format a range starting at this byte offset.\n"
+                 "Multiple ranges can be formatted by specifying\n"
+                 "several -offset and -length pairs.\n"
+                 "Can only be used with one input file.">;
+defm length : Eq<"length", "<uint>",
+                 "Format a range of this length (in bytes).\n"
+                 "Multiple ranges can be formatted by specifying\n"
+                 "several -offset and -length pairs.\n"
+                 "When only a single -offset is specified without\n"
+                 "-length, clang-format will format up to the end\n"
+                 "of the file.\n"
+                 "Can only be used with one input file.">;
+defm lines : Eq<"lines", "<start line>:<end line>",
+                "Format a range of lines (both 1-based).\n"
+                "Multiple ranges can be formatted by specifying\n"
+                "several -lines arguments.\n"
+                "Can't be used with -offset and -length.\n"
+                "Can only be used with one input file.">;
+defm style : Eq<"style", "<string>",
+                "Set coding style. <string> can be:\n"
+                "1. A preset: LLVM, GNU, Google, Chromium, Microsoft,\n"
+                "   Mozilla, WebKit.\n"
+                "2. 'file' to load style configuration from a\n"
+                "   .clang-format file in one of the parent directories\n"
+                "   of the source file (for stdin, see --assume-filename).\n"
+                "   If no .clang-format file is found, falls back to\n"
+                "   --fallback-style.\n"
+                "   --style=file is the default.\n"
+                "3. 'file:<format_file_path>' to explicitly specify\n"
+                "   the configuration file.\n"
+                "4. \"{key: value, ...}\" to set specific parameters, e.g.:\n"
+                "   --style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"">;
+defm fallback_style : Eq<"fallback-style", "<string>",
+                         "The name of the predefined style used as a\n"
+                         "fallback in case clang-format is invoked with\n"
+                         "-style=file, but can not find the .clang-format\n"
+                         "file to use. Defaults to 'LLVM'.\n"
+                         "Use -fallback-style=none to skip formatting.">;
+defm assume_filename : Eq<"assume-filename", "<string>",
+                         "Set filename used to determine the language and to "
+                         "find\n"
+                         ".clang-format file.\n"
+                         "Only used when reading from stdin.\n"
+                         "If this is not passed, the .clang-format file is "
+                         "searched\n"
+                         "relative to the current working directory when "
+                         "reading stdin.\n"
+                         "Unrecognized filenames are treated as C++.\n"
+                         "supported:\n"
+                         "  CSharp: .cs\n"
+                         "  Java: .java\n"
+                         "  JavaScript: .js .mjs .cjs .ts\n"
+                         "  JSON: .json .ipynb\n"
+                         "  Objective-C: .m .mm\n"
+                         "  Proto: .proto .protodevel\n"
+                         "  TableGen: .td\n"
+                         "  TextProto: .txtpb .textpb .pb.txt .textproto "
+                         ".asciipb\n"
+                         "  Verilog: .sv .svh .v .vh">;
+
+defm i : B<"i", "Inplace edit <file>s, if specified.">;
+defm output_replacements_xml
+    : B<"output-replacements-xml", "Output replacements as XML.">;
+defm dump_config : B<"dump-config",
+                     "Dump configuration options to stdout and exit.\n"
+                     "Can be used with -style option.">;
+defm cursor : Eq<"cursor", "<uint>",
+                 "The position of the cursor when invoking\n"
+                 "clang-format from an editor integration">;
+defm sort_includes
+    : B<"sort-includes",
+        "If set, overrides the include sorting behavior\n"
+        "determined by the SortIncludes style flag">;
+defm qualifier_alignment
+    : Eq<"qualifier-alignment", "<string>",
+         "If set, overrides the qualifier alignment style\n"
+         "determined by the QualifierAlignment style flag">;
+defm files : Eq<"files", "<filename>",
+                "A file containing a list of files to process, one per line.">;
+defm verbose
+    : B<"verbose", "If set, shows the list of processed files">;
+defm dry_run
+    : B<"dry-run", "If set, do not actually make the formatting changes">;
+def n : F<"n", "Alias for --dry-run">, Alias<dry_run>;
+
+defm Wclang_format_violations
+    : BH<"Wclang-format-violations",
+         "Warnings about individual formatting changes needed. Used only with "
+         "--dry-run or -n">;
+defm Wno_clang_format_violations
+    : BH<"Wno-clang-format-violations",
+         "Do not warn about individual formatting changes needed. Used only "
+         "with --dry-run or -n">;
+defm ferror_limit
+    : Eq<"ferror-limit", "<uint>",
+         "Set the maximum number of clang-format errors to emit\n"
+         "before stopping (0 = no limit).\n"
+         "Used only with --dry-run or -n">;
+defm Werror
+    : B<"Werror", "If set, changes formatting warnings to errors">;
+defm Wno_error
+    : Eq<"Wno-error", "<warning>",
+         "If set, don't error out on the specified warning type.\n"
+         "Supported warnings:\n"
+         "  unknown - unknown format options are only warned about.\n"
+         "This can be used to enable formatting, even if the\n"
+         "configuration contains unknown (newer) options.\n"
+         "Use with caution, as this might lead to dramatically\n"
+         "differing format depending on an option being\n"
+         "supported or not.">;
+defm fcolor_diagnostics
+    : BH<"fcolor-diagnostics",
+         "If set, and on a color-capable terminal controls whether or not to "
+         "print diagnostics in color">;
+defm fno_color_diagnostics
+    : BH<"fno-color-diagnostics",
+         "If set, and on a color-capable terminal controls whether or not to "
+         "print diagnostics in color">;
+defm fail_on_incomplete_format
+    : B<"fail-on-incomplete-format",
+        "If set, fail with exit code 1 on incomplete format.">;
+defm list_ignored : BH<"list-ignored", "List ignored files.">;
diff --git a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel 
b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
index 819b6b9dcfbfd..a57334ae7557c 100644
--- a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
@@ -2402,22 +2402,38 @@ cc_binary(
     ],
 )
 
-cc_binary(
-    name = "clang-format",
+gentbl_cc_library(
+    name = "ClangFormatOptsTableGen",
+    strip_include_prefix = "tools/clang-format",
+    tbl_outs = {"tools/clang-format/Opts.inc": ["-gen-opt-parser-defs"]},
+    tblgen = "//llvm:llvm-tblgen",
+    td_file = "tools/clang-format/Opts.td",
+    deps = ["//llvm:OptParserTdFiles"],
+)
+
+cc_library(
+    name = "clang-format-lib",
     srcs = [
         "lib/Format/MatchFilePath.h",
         "tools/clang-format/ClangFormat.cpp",
     ],
-    stamp = 0,
     deps = [
+        ":ClangFormatOptsTableGen",
         ":basic",
         ":format",
         ":frontend",
         ":rewrite",
+        "//llvm:Option",
         "//llvm:Support",
     ],
 )
 
+llvm_driver_cc_binary(
+    name = "clang-format",
+    stamp = 0,
+    deps = [":clang-format-lib"],
+)
+
 cc_binary(
     name = "clang-diff",
     srcs = glob(["tools/clang-diff/*.cpp"]),
diff --git a/utils/bazel/llvm-project-overlay/llvm/driver.bzl 
b/utils/bazel/llvm-project-overlay/llvm/driver.bzl
index 478e0205aeed5..6b44d1b67f98e 100644
--- a/utils/bazel/llvm-project-overlay/llvm/driver.bzl
+++ b/utils/bazel/llvm-project-overlay/llvm/driver.bzl
@@ -10,6 +10,7 @@ load("@rules_cc//cc:defs.bzl", "CcInfo", "cc_binary")
 
 # Mapping from every tool to the cc_library that implements the tool's 
entrypoint.
 _TOOLS = {
+    "clang-format": "//clang:clang-format-lib",
     "clang-scan-deps": "//clang:clang-scan-deps-lib",
     "clang": "//clang:clang-driver",
     "dsymutil": "//llvm:dsymutil-lib",

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to