[clang] [clang-tools-extra] [lld] [llvm] [llvm] Add subcommand support for OptTable (PR #155026)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 26 11:22:37 PDT 2025


================
@@ -0,0 +1,227 @@
+//===- unittest/Support/OptionParsingTest.cpp - OptTable tests ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::opt;
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+namespace {
+enum ID {
+  OPT_INVALID = 0,
+#define OPTION(PREFIXES, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,       \
+               VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR,     \
+               VALUES, SUBCOMMANDIDS_OFFSET)                                   \
+  OPT_##ID,
+#include "SubCommandOpts.inc"
+#undef OPTION
+};
+#define OPTTABLE_STR_TABLE_CODE
+#include "SubCommandOpts.inc"
+#undef OPTTABLE_STR_TABLE_CODE
+
+#define OPTTABLE_PREFIXES_TABLE_CODE
+#include "SubCommandOpts.inc"
+#undef OPTTABLE_PREFIXES_TABLE_CODE
+
+#define OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE
+#include "SubCommandOpts.inc"
+#undef OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE
+
+#define OPTTABLE_SUBCOMMANDS_CODE
+#include "SubCommandOpts.inc"
+#undef OPTTABLE_SUBCOMMANDS_CODE
+
+static constexpr OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#include "SubCommandOpts.inc"
+#undef OPTION
+};
+
+class TestOptSubCommandTable : public GenericOptTable {
+public:
+  TestOptSubCommandTable(bool IgnoreCase = false)
+      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
+                        /*IgnoreCase=*/false, OptionSubCommands,
+                        OptionSubCommandIDsTable) {}
+};
+
+// Test fixture
+template <typename T> class OptSubCommandTableTest : public ::testing::Test {};
+
+// Test both precomputed and computed OptTables with the same suite of tests.
+using OptSubCommandTableTestTypes = ::testing::Types<TestOptSubCommandTable>;
+
+TYPED_TEST_SUITE(OptSubCommandTableTest, OptSubCommandTableTestTypes, );
+
+TYPED_TEST(OptSubCommandTableTest, SubCommandParsing) {
+  TypeParam T;
+  unsigned MAI, MAC;
+
+  std::string ErrMsg;
+  raw_string_ostream RSO1(ErrMsg);
+
+  auto HandleMultipleSubcommands = [&](ArrayRef<StringRef> SubCommands) {
+    ErrMsg.clear();
+    RSO1 << "Multiple subcommands passed\n";
+    for (auto SC : SubCommands) {
+      RSO1 << "\n" << SC;
+    }
+  };
+
+  auto HandleOtherPositionals = [&](ArrayRef<StringRef> Positionals) {
+    ErrMsg.clear();
+    RSO1 << "Unregistered positionals passed\n";
+    for (auto SC : Positionals) {
+      RSO1 << "\n" << SC;
+    }
+  };
+
+  {
+    // Test case 1: Toplevel option, no subcommand
+    const char *Args[] = {"-version"};
+    InputArgList AL = T.ParseArgs(Args, MAI, MAC);
+    EXPECT_TRUE(AL.hasArg(OPT_version));
+    StringRef SC = AL.getSubcommand(
+        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);
+    EXPECT_TRUE(SC.empty());
+    EXPECT_FALSE(AL.hasArg(OPT_uppercase));
+    EXPECT_FALSE(AL.hasArg(OPT_lowercase));
+  }
+
+  {
+    // Test case 2: Subcommand 'foo' with its valid options
+    const char *Args[] = {"foo", "-uppercase"};
+    InputArgList AL = T.ParseArgs(Args, MAI, MAC);
+    StringRef SC = AL.getSubcommand(
+        T.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);
+    EXPECT_EQ(SC, "foo");
+    EXPECT_TRUE(AL.hasArg(OPT_uppercase));
+    EXPECT_FALSE(AL.hasArg(OPT_lowercase));
+    EXPECT_FALSE(AL.hasArg(OPT_version));
+    // Do not expect any error messages as this is a valid use case.
----------------
PiJoules wrote:

Since you're using gtest, it might be more verbose if the comment was part of the error message on an expect failure, so something like:

```
EXPECT_EQ(std::string::npos, ErrMsg.find("Multiple subcommands passed")) << "Do not expect any error messages as this is a valid use case.";
```

same might be good for other comments above individual EXPECT lines below.

https://github.com/llvm/llvm-project/pull/155026


More information about the llvm-commits mailing list