jingham created this revision.
jingham added reviewers: JDevlieghere, clayborg, kastiglione, ADodds.
Herald added a project: All.
jingham requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

At present, if a command takes no arguments, it's required to check by hand 
that it hasn't been passed an argument.  That's  error-prone and unnecessary, 
since CommandObject has a way for sub-classes to register what arguments it 
takes, and that could be checked directly after the command line parse.  I only 
do this for CommandObjectParsed.  There isn't enough information to do a 
generic check for CommandObjectRaw, since these are explicitly unstructured 
commands.

This patch has four parts:

1. The tiny bit of code in CommandObjectParsed::Execute that does the check
2. Fixing up the handful of commands that hadn't registered their arguments (up 
to now this was not required)

These were pretty straightforward.  I did have to fix up a bunch of the 
RenderScript commands.  I don't know
who's responsible for the Renderscript plugin these days, so I picked one of 
the more recent contributors to
that file at random...

3. Removing all the ad hoc checks for arguments passed to commands that don't 
take them
4. Fixing up the tests that relied on the exact wording of the ad hoc errors

We can do a lot more with the argument info - automating completions and 
validation of arguments for commands that do take them.  But here I'm only 
dealing with the automatic error generation for commands that take no arguments.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D128453

Files:
  lldb/include/lldb/lldb-enumerations.h
  lldb/source/API/SBCommandInterpreter.cpp
  lldb/source/Commands/CommandObjectCommands.cpp
  lldb/source/Commands/CommandObjectFrame.cpp
  lldb/source/Commands/CommandObjectGUI.cpp
  lldb/source/Commands/CommandObjectPlatform.cpp
  lldb/source/Commands/CommandObjectProcess.cpp
  lldb/source/Commands/CommandObjectQuit.cpp
  lldb/source/Commands/CommandObjectReproducer.cpp
  lldb/source/Commands/CommandObjectSource.cpp
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Commands/CommandObjectThreadUtil.cpp
  lldb/source/Commands/CommandObjectTrace.cpp
  lldb/source/Commands/CommandObjectType.cpp
  lldb/source/Commands/CommandObjectVersion.cpp
  lldb/source/Interpreter/CommandObject.cpp
  
lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
  
lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
  lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  lldb/test/API/commands/gui/invalid-args/TestInvalidArgsGui.py
  lldb/test/API/commands/reproducer/invalid-args/TestInvalidArgsReproducer.py
  lldb/test/API/commands/target/basic/TestTargetCommand.py
  lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py
  lldb/test/API/commands/version/TestVersion.py
  
lldb/test/API/commands/watchpoints/multi_watchpoint_slots/TestWatchpointMultipleSlots.py
  lldb/test/API/functionalities/completion/TestCompletion.py

Index: lldb/test/API/functionalities/completion/TestCompletion.py
===================================================================
--- lldb/test/API/functionalities/completion/TestCompletion.py
+++ lldb/test/API/functionalities/completion/TestCompletion.py
@@ -675,7 +675,7 @@
 
         self.build()
         self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
-        self.runCmd('target stop-hook add test DONE')
+        self.runCmd('target stop-hook add -o test')
 
         for subcommand in subcommands:
             self.complete_from_to('target stop-hook ' + subcommand + ' ',
Index: lldb/test/API/commands/watchpoints/multi_watchpoint_slots/TestWatchpointMultipleSlots.py
===================================================================
--- lldb/test/API/commands/watchpoints/multi_watchpoint_slots/TestWatchpointMultipleSlots.py
+++ lldb/test/API/commands/watchpoints/multi_watchpoint_slots/TestWatchpointMultipleSlots.py
@@ -88,10 +88,10 @@
         # The stop reason of the thread should be watchpoint.
         if self.platformIsDarwin():
             # On darwin we'll hit byteArray[3] which is watchpoint 2
-            self.expect("thread list -v", STOPPED_DUE_TO_WATCHPOINT,
+            self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
                         substrs=['stopped', 'stop reason = watchpoint 2'])
         else:
-            self.expect("thread list -v", STOPPED_DUE_TO_WATCHPOINT,
+            self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
                         substrs=['stopped', 'stop reason = watchpoint 3'])
 
         # Resume inferior.
Index: lldb/test/API/commands/version/TestVersion.py
===================================================================
--- lldb/test/API/commands/version/TestVersion.py
+++ lldb/test/API/commands/version/TestVersion.py
@@ -14,4 +14,4 @@
     @no_debug_info_test
     def test_version_invalid_invocation(self):
         self.expect("version a", error=True,
-                    substrs=['the version command takes no arguments.'])
+                    substrs=["'version' doesn't take any arguments."])
Index: lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py
===================================================================
--- lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py
+++ lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py
@@ -28,4 +28,4 @@
         self.build()
         self.createTestTarget()
         self.expect("target dump typesystem arg", error=True,
-                    substrs=["error: target dump typesystem doesn't take arguments."])
+                    substrs=["'target dump typesystem' doesn't take any arguments."])
Index: lldb/test/API/commands/target/basic/TestTargetCommand.py
===================================================================
--- lldb/test/API/commands/target/basic/TestTargetCommand.py
+++ lldb/test/API/commands/target/basic/TestTargetCommand.py
@@ -325,7 +325,7 @@
     @no_debug_info_test
     def test_target_list_args(self):
         self.expect("target list blub", error=True,
-                    substrs=["the 'target list' command takes no arguments"])
+                    substrs=["'target list' doesn't take any arguments"])
 
     @no_debug_info_test
     def test_target_select_no_index(self):
Index: lldb/test/API/commands/reproducer/invalid-args/TestInvalidArgsReproducer.py
===================================================================
--- lldb/test/API/commands/reproducer/invalid-args/TestInvalidArgsReproducer.py
+++ lldb/test/API/commands/reproducer/invalid-args/TestInvalidArgsReproducer.py
@@ -7,9 +7,9 @@
     @no_debug_info_test
     def test_reproducer_generate_invalid_invocation(self):
         self.expect("reproducer generate f", error=True,
-                    substrs=["'reproducer generate' takes no arguments"])
+                    substrs=["'reproducer generate' doesn't take any arguments"])
 
     @no_debug_info_test
     def test_reproducer_status_invalid_invocation(self):
         self.expect("reproducer status f", error=True,
-                    substrs=["'reproducer status' takes no arguments"])
+                    substrs=["'reproducer status' doesn't take any arguments"])
Index: lldb/test/API/commands/gui/invalid-args/TestInvalidArgsGui.py
===================================================================
--- lldb/test/API/commands/gui/invalid-args/TestInvalidArgsGui.py
+++ lldb/test/API/commands/gui/invalid-args/TestInvalidArgsGui.py
@@ -8,4 +8,4 @@
     @skipIfCursesSupportMissing
     def test_reproducer_generate_invalid_invocation(self):
         self.expect("gui blub", error=True,
-                    substrs=["the gui command takes no arguments."])
+                    substrs=["'gui' doesn't take any arguments."])
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5008,19 +5008,12 @@
   ~CommandObjectProcessGDBRemotePacketHistory() override = default;
 
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    const size_t argc = command.GetArgumentCount();
-    if (argc == 0) {
-      ProcessGDBRemote *process =
-          (ProcessGDBRemote *)m_interpreter.GetExecutionContext()
-              .GetProcessPtr();
-      if (process) {
-        process->GetGDBRemote().DumpHistory(result.GetOutputStream());
-        result.SetStatus(eReturnStatusSuccessFinishResult);
-        return true;
-      }
-    } else {
-      result.AppendErrorWithFormat("'%s' takes no arguments",
-                                   m_cmd_name.c_str());
+    ProcessGDBRemote *process =
+        (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+    if (process) {
+      process->GetGDBRemote().DumpHistory(result.GetOutputStream());
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+      return true;
     }
     result.SetStatus(eReturnStatusFailed);
     return false;
@@ -5034,7 +5027,10 @@
       : CommandObjectParsed(
             interpreter, "process plugin packet xfer-size",
             "Maximum size that lldb will try to read/write one one chunk.",
-            nullptr) {}
+            nullptr) {
+    CommandArgumentData max_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    m_arguments.push_back({max_arg});
+  }
 
   ~CommandObjectProcessGDBRemotePacketXferSize() override = default;
 
@@ -5075,7 +5071,10 @@
                             "The packet header and footer will automatically "
                             "be added to the packet prior to sending and "
                             "stripped from the result.",
-                            nullptr) {}
+                            nullptr) {
+    CommandArgumentData packet_arg{eArgTypeNone, eArgRepeatStar};
+    m_arguments.push_back({packet_arg});
+  }
 
   ~CommandObjectProcessGDBRemotePacketSend() override = default;
 
Index: lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
===================================================================
--- lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -883,87 +883,81 @@
   ~CommandObjectProcessKDPPacketSend() override = default;
 
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    const size_t argc = command.GetArgumentCount();
-    if (argc == 0) {
-      if (!m_command_byte.GetOptionValue().OptionWasSet()) {
-        result.AppendError(
-            "the --command option must be set to a valid command byte");
-      } else {
-        const uint64_t command_byte =
-            m_command_byte.GetOptionValue().GetUInt64Value(0);
-        if (command_byte > 0 && command_byte <= UINT8_MAX) {
-          ProcessKDP *process =
-              (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr();
-          if (process) {
-            const StateType state = process->GetState();
-
-            if (StateIsStoppedState(state, true)) {
-              std::vector<uint8_t> payload_bytes;
-              const char *ascii_hex_bytes_cstr =
-                  m_packet_data.GetOptionValue().GetCurrentValue();
-              if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) {
-                StringExtractor extractor(ascii_hex_bytes_cstr);
-                const size_t ascii_hex_bytes_cstr_len =
-                    extractor.GetStringRef().size();
-                if (ascii_hex_bytes_cstr_len & 1) {
-                  result.AppendErrorWithFormat("payload data must contain an "
-                                               "even number of ASCII hex "
-                                               "characters: '%s'",
-                                               ascii_hex_bytes_cstr);
-                  return false;
-                }
-                payload_bytes.resize(ascii_hex_bytes_cstr_len / 2);
-                if (extractor.GetHexBytes(payload_bytes, '\xdd') !=
-                    payload_bytes.size()) {
-                  result.AppendErrorWithFormat("payload data must only contain "
-                                               "ASCII hex characters (no "
-                                               "spaces or hex prefixes): '%s'",
-                                               ascii_hex_bytes_cstr);
-                  return false;
-                }
+    if (!m_command_byte.GetOptionValue().OptionWasSet()) {
+      result.AppendError(
+          "the --command option must be set to a valid command byte");
+    } else {
+      const uint64_t command_byte =
+          m_command_byte.GetOptionValue().GetUInt64Value(0);
+      if (command_byte > 0 && command_byte <= UINT8_MAX) {
+        ProcessKDP *process =
+            (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr();
+        if (process) {
+          const StateType state = process->GetState();
+
+          if (StateIsStoppedState(state, true)) {
+            std::vector<uint8_t> payload_bytes;
+            const char *ascii_hex_bytes_cstr =
+                m_packet_data.GetOptionValue().GetCurrentValue();
+            if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) {
+              StringExtractor extractor(ascii_hex_bytes_cstr);
+              const size_t ascii_hex_bytes_cstr_len =
+                  extractor.GetStringRef().size();
+              if (ascii_hex_bytes_cstr_len & 1) {
+                result.AppendErrorWithFormat("payload data must contain an "
+                                             "even number of ASCII hex "
+                                             "characters: '%s'",
+                                             ascii_hex_bytes_cstr);
+                return false;
               }
-              Status error;
-              DataExtractor reply;
-              process->GetCommunication().SendRawRequest(
-                  command_byte,
-                  payload_bytes.empty() ? NULL : payload_bytes.data(),
-                  payload_bytes.size(), reply, error);
-
-              if (error.Success()) {
-                // Copy the binary bytes into a hex ASCII string for the result
-                StreamString packet;
-                packet.PutBytesAsRawHex8(
-                    reply.GetDataStart(), reply.GetByteSize(),
-                    endian::InlHostByteOrder(), endian::InlHostByteOrder());
-                result.AppendMessage(packet.GetString());
-                result.SetStatus(eReturnStatusSuccessFinishResult);
-                return true;
-              } else {
-                const char *error_cstr = error.AsCString();
-                if (error_cstr && error_cstr[0])
-                  result.AppendError(error_cstr);
-                else
-                  result.AppendErrorWithFormat("unknown error 0x%8.8x",
-                                               error.GetError());
+              payload_bytes.resize(ascii_hex_bytes_cstr_len / 2);
+              if (extractor.GetHexBytes(payload_bytes, '\xdd') !=
+                  payload_bytes.size()) {
+                result.AppendErrorWithFormat("payload data must only contain "
+                                             "ASCII hex characters (no "
+                                             "spaces or hex prefixes): '%s'",
+                                             ascii_hex_bytes_cstr);
                 return false;
               }
+            }
+            Status error;
+            DataExtractor reply;
+            process->GetCommunication().SendRawRequest(
+                command_byte,
+                payload_bytes.empty() ? NULL : payload_bytes.data(),
+                payload_bytes.size(), reply, error);
+
+            if (error.Success()) {
+              // Copy the binary bytes into a hex ASCII string for the result
+              StreamString packet;
+              packet.PutBytesAsRawHex8(
+                  reply.GetDataStart(), reply.GetByteSize(),
+                  endian::InlHostByteOrder(), endian::InlHostByteOrder());
+              result.AppendMessage(packet.GetString());
+              result.SetStatus(eReturnStatusSuccessFinishResult);
+              return true;
             } else {
-              result.AppendErrorWithFormat("process must be stopped in order "
-                                           "to send KDP packets, state is %s",
-                                           StateAsCString(state));
+              const char *error_cstr = error.AsCString();
+              if (error_cstr && error_cstr[0])
+                result.AppendError(error_cstr);
+              else
+                result.AppendErrorWithFormat("unknown error 0x%8.8x",
+                                             error.GetError());
+              return false;
             }
           } else {
-            result.AppendError("invalid process");
+            result.AppendErrorWithFormat("process must be stopped in order "
+                                         "to send KDP packets, state is %s",
+                                         StateAsCString(state));
           }
         } else {
-          result.AppendErrorWithFormat("invalid command byte 0x%" PRIx64
-                                       ", valid values are 1 - 255",
-                                       command_byte);
+          result.AppendError("invalid process");
         }
+      } else {
+        result.AppendErrorWithFormat("invalid command byte 0x%" PRIx64
+                                     ", valid values are 1 - 255",
+                                     command_byte);
       }
-    } else {
-      result.AppendErrorWithFormat("'%s' takes no arguments, only options.",
-                                   m_cmd_name.c_str());
     }
     return false;
   }
Index: lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
===================================================================
--- lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
+++ lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
@@ -39,7 +39,10 @@
             interpreter, "renderscript scriptgroup breakpoint set",
             "Place a breakpoint on all kernels forming a script group.",
             "renderscript scriptgroup breakpoint set <group_name>",
-            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
+            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
+    CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlus};
+    m_arguments.push_back({name_arg});
+  }
 
   ~CommandObjectRenderScriptScriptGroupBreakpointSet() override = default;
 
Index: lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
===================================================================
--- lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
+++ lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
@@ -4067,7 +4067,10 @@
             "<reduction_kernel_type,...>]",
             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
                 eCommandProcessMustBePaused),
-        m_options(){};
+        m_options() {
+    CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlain};
+    m_arguments.push_back({name_arg});
+  };
 
   class CommandOptions : public Options {
   public:
@@ -4216,7 +4219,10 @@
             "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
                 eCommandProcessMustBePaused),
-        m_options() {}
+        m_options() {
+    CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlain};
+    m_arguments.push_back({name_arg});
+  }
 
   ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
 
@@ -4311,7 +4317,10 @@
             "but does not remove currently set breakpoints.",
             "renderscript kernel breakpoint all <enable/disable>",
             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
-                eCommandProcessMustBePaused) {}
+                eCommandProcessMustBePaused) {
+    CommandArgumentData enable_arg{eArgTypeNone, eArgRepeatPlain};
+    m_arguments.push_back({enable_arg});
+  }
 
   ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
 
@@ -4493,7 +4502,10 @@
                             "renderscript allocation dump <ID>",
                             eCommandRequiresProcess |
                                 eCommandProcessMustBeLaunched),
-        m_options() {}
+        m_options() {
+    CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    m_arguments.push_back({id_arg});
+  }
 
   ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
 
@@ -4679,7 +4691,12 @@
             interpreter, "renderscript allocation load",
             "Loads renderscript allocation contents from a file.",
             "renderscript allocation load <ID> <filename>",
-            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
+            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
+    CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    CommandArgumentData name_arg{eArgTypeFilename, eArgRepeatPlain};
+    m_arguments.push_back({id_arg});
+    m_arguments.push_back({name_arg});
+  }
 
   ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
 
@@ -4726,7 +4743,12 @@
                             "Write renderscript allocation contents to a file.",
                             "renderscript allocation save <ID> <filename>",
                             eCommandRequiresProcess |
-                                eCommandProcessMustBeLaunched) {}
+                                eCommandProcessMustBeLaunched) {
+    CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    CommandArgumentData name_arg{eArgTypeFilename, eArgRepeatPlain};
+    m_arguments.push_back({id_arg});
+    m_arguments.push_back({name_arg});
+  }
 
   ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
 
Index: lldb/source/Interpreter/CommandObject.cpp
===================================================================
--- lldb/source/Interpreter/CommandObject.cpp
+++ lldb/source/Interpreter/CommandObject.cpp
@@ -995,6 +995,11 @@
       if (ParseOptions(cmd_args, result)) {
         // Call the command-specific version of 'Execute', passing it the
         // already processed arguments.
+        if (cmd_args.GetArgumentCount() != 0 && m_arguments.empty()) {
+          result.AppendErrorWithFormatv("'{0}' doesn't take any arguments.",
+                                        GetCommandName());
+          return false;
+        }
         handled = DoExecute(cmd_args, result);
       }
     }
@@ -1126,7 +1131,11 @@
     { eArgTypeCommand, "command", CommandCompletions::eNoCompletion, { nullptr, false }, "An LLDB Command line command element." },
     { eArgTypeColumnNum, "column", CommandCompletions::eNoCompletion, { nullptr, false }, "Column number in a source file." },
     { eArgTypeModuleUUID, "module-uuid", CommandCompletions::eModuleUUIDCompletion, { nullptr, false }, "A module UUID value." },
-    { eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." }
+    { eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." },
+    { eArgTypeSEDStylePair, "substitution-pair", CommandCompletions::eNoCompletion, { nullptr, false }, "A sed-style pattern and target pair." },
+    { eArgTypeConnectURL, "process-connect-url", CommandCompletions::eNoCompletion, { nullptr, false }, "A URL-style specification for a remote connection." },
+    { eArgTypeTargetID, "target-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The index ID for an lldb Target." },
+    { eArgTypeStopHookID, "stop-hook-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The ID you receive when you create a stop-hook." }
     // clang-format on
 };
 
Index: lldb/source/Commands/CommandObjectVersion.cpp
===================================================================
--- lldb/source/Commands/CommandObjectVersion.cpp
+++ lldb/source/Commands/CommandObjectVersion.cpp
@@ -23,11 +23,7 @@
 CommandObjectVersion::~CommandObjectVersion() = default;
 
 bool CommandObjectVersion::DoExecute(Args &args, CommandReturnObject &result) {
-  if (args.GetArgumentCount() == 0) {
-    result.AppendMessageWithFormat("%s\n", lldb_private::GetVersion());
-    result.SetStatus(eReturnStatusSuccessFinishResult);
-  } else {
-    result.AppendError("the version command takes no arguments.");
-  }
+  result.AppendMessageWithFormat("%s\n", lldb_private::GetVersion());
+  result.SetStatus(eReturnStatusSuccessFinishResult);
   return true;
 }
Index: lldb/source/Commands/CommandObjectType.cpp
===================================================================
--- lldb/source/Commands/CommandObjectType.cpp
+++ lldb/source/Commands/CommandObjectType.cpp
@@ -914,7 +914,10 @@
                                   uint32_t formatter_kind_mask,
                                   const char *name, const char *help)
       : CommandObjectParsed(interpreter, name, help, nullptr),
-        m_formatter_kind_mask(formatter_kind_mask) {}
+        m_formatter_kind_mask(formatter_kind_mask) {
+    CommandArgumentData category_arg{eArgTypeName, eArgRepeatOptional};
+    m_arguments.push_back({category_arg});
+  }
 
   ~CommandObjectTypeFormatterClear() override = default;
 
Index: lldb/source/Commands/CommandObjectTrace.cpp
===================================================================
--- lldb/source/Commands/CommandObjectTrace.cpp
+++ lldb/source/Commands/CommandObjectTrace.cpp
@@ -74,7 +74,10 @@
   CommandObjectTraceLoad(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "trace load",
                             "Load a processor trace session from a JSON file.",
-                            "trace load") {}
+                            "trace load <json_session_file>") {
+    CommandArgumentData session_file_arg{eArgTypePath, eArgRepeatPlain};
+    m_arguments.push_back({session_file_arg});
+  }
 
   ~CommandObjectTraceLoad() override = default;
 
@@ -223,7 +226,10 @@
       : CommandObjectParsed(interpreter, "trace schema",
                             "Show the schema of the given trace plugin.",
                             "trace schema <plug-in>. Use the plug-in name "
-                            "\"all\" to see all schemas.\n") {}
+                            "\"all\" to see all schemas.\n") {
+    CommandArgumentData plugin_arg{eArgTypeNone, eArgRepeatPlain};
+    m_arguments.push_back({plugin_arg});
+  }
 
   ~CommandObjectTraceSchema() override = default;
 
Index: lldb/source/Commands/CommandObjectThreadUtil.cpp
===================================================================
--- lldb/source/Commands/CommandObjectThreadUtil.cpp
+++ lldb/source/Commands/CommandObjectThreadUtil.cpp
@@ -19,7 +19,11 @@
 CommandObjectIterateOverThreads::CommandObjectIterateOverThreads(
     CommandInterpreter &interpreter, const char *name, const char *help,
     const char *syntax, uint32_t flags)
-    : CommandObjectParsed(interpreter, name, help, syntax, flags) {}
+    : CommandObjectParsed(interpreter, name, help, syntax, flags) {
+  // These commands all take thread ID's as arguments.
+  CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatStar};
+  m_arguments.push_back({thread_arg});
+}
 
 bool CommandObjectIterateOverThreads::DoExecute(Args &command,
                                                 CommandReturnObject &result) {
Index: lldb/source/Commands/CommandObjectTarget.cpp
===================================================================
--- lldb/source/Commands/CommandObjectTarget.cpp
+++ lldb/source/Commands/CommandObjectTarget.cpp
@@ -487,18 +487,14 @@
 
 protected:
   bool DoExecute(Args &args, CommandReturnObject &result) override {
-    if (args.GetArgumentCount() == 0) {
-      Stream &strm = result.GetOutputStream();
+    Stream &strm = result.GetOutputStream();
 
-      bool show_stopped_process_status = false;
-      if (DumpTargetList(GetDebugger().GetTargetList(),
-                         show_stopped_process_status, strm) == 0) {
-        strm.PutCString("No targets.\n");
-      }
-      result.SetStatus(eReturnStatusSuccessFinishResult);
-    } else {
-      result.AppendError("the 'target list' command takes no arguments\n");
+    bool show_stopped_process_status = false;
+    if (DumpTargetList(GetDebugger().GetTargetList(),
+                       show_stopped_process_status, strm) == 0) {
+      strm.PutCString("No targets.\n");
     }
+    result.SetStatus(eReturnStatusSuccessFinishResult);
     return result.Succeeded();
   }
 };
@@ -511,6 +507,8 @@
       : CommandObjectParsed(
             interpreter, "target select",
             "Select a target as the current target by target index.", nullptr) {
+    CommandArgumentData target_arg{eArgTypeTargetID, eArgRepeatPlain};
+    m_arguments.push_back({target_arg});
   }
 
   ~CommandObjectTargetSelect() override = default;
@@ -575,6 +573,8 @@
     m_option_group.Append(&m_all_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
     m_option_group.Append(&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
     m_option_group.Finalize();
+    CommandArgumentData target_arg{eArgTypeTargetID, eArgRepeatStar};
+    m_arguments.push_back({target_arg});
   }
 
   ~CommandObjectTargetDelete() override = default;
@@ -1230,10 +1230,6 @@
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
     Target *target = &GetSelectedTarget();
-    if (command.GetArgumentCount() != 0) {
-      result.AppendError("list takes no arguments\n");
-      return result.Succeeded();
-    }
 
     target->GetImageSearchPathList().Dump(&result.GetOutputStream());
     result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -2454,6 +2450,8 @@
                           LLDB_OPT_SET_1);
     m_option_group.Append(&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
     m_option_group.Finalize();
+    CommandArgumentData module_arg{eArgTypePath, eArgRepeatStar};
+    m_arguments.push_back({module_arg});
   }
 
   ~CommandObjectTargetModulesAdd() override = default;
@@ -4019,6 +4017,8 @@
     m_option_group.Append(&m_current_stack_option, LLDB_OPT_SET_2,
                           LLDB_OPT_SET_2);
     m_option_group.Finalize();
+    CommandArgumentData module_arg{eArgTypeShlibName, eArgRepeatPlain};
+    m_arguments.push_back({module_arg});
   }
 
   ~CommandObjectTargetSymbolsAdd() override = default;
@@ -4867,7 +4867,10 @@
   CommandObjectTargetStopHookDelete(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "target stop-hook delete",
                             "Delete a stop-hook.",
-                            "target stop-hook delete [<idx>]") {}
+                            "target stop-hook delete [<idx>]") {
+    CommandArgumentData hook_arg{eArgTypeStopHookID, eArgRepeatStar};
+    m_arguments.push_back({hook_arg});
+  }
 
   ~CommandObjectTargetStopHookDelete() override = default;
 
@@ -4921,6 +4924,8 @@
                                            bool enable, const char *name,
                                            const char *help, const char *syntax)
       : CommandObjectParsed(interpreter, name, help, syntax), m_enable(enable) {
+    CommandArgumentData hook_arg{eArgTypeStopHookID, eArgRepeatStar};
+    m_arguments.push_back({hook_arg});
   }
 
   ~CommandObjectTargetStopHookEnableDisable() override = default;
@@ -4976,8 +4981,7 @@
 public:
   CommandObjectTargetStopHookList(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "target stop-hook list",
-                            "List all stop-hooks.",
-                            "target stop-hook list [<type>]") {}
+                            "List all stop-hooks.", "target stop-hook list") {}
 
   ~CommandObjectTargetStopHookList() override = default;
 
@@ -5049,11 +5053,6 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (!command.empty()) {
-      result.AppendError("target dump typesystem doesn't take arguments.");
-      return result.Succeeded();
-    }
-
     // Go over every scratch TypeSystem and dump to the command output.
     for (TypeSystem *ts : GetSelectedTarget().GetScratchTypeSystems())
       ts->Dump(result.GetOutputStream().AsRawOstream());
Index: lldb/source/Commands/CommandObjectSource.cpp
===================================================================
--- lldb/source/Commands/CommandObjectSource.cpp
+++ lldb/source/Commands/CommandObjectSource.cpp
@@ -538,14 +538,6 @@
   }
 
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    const size_t argc = command.GetArgumentCount();
-
-    if (argc != 0) {
-      result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
-                                   GetCommandName().str().c_str());
-      return false;
-    }
-
     Target *target = m_exe_ctx.GetTargetPtr();
     if (target == nullptr) {
       target = GetDebugger().GetSelectedTarget().get();
@@ -924,14 +916,6 @@
   }
 
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    const size_t argc = command.GetArgumentCount();
-
-    if (argc != 0) {
-      result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
-                                   GetCommandName().str().c_str());
-      return false;
-    }
-
     Target *target = m_exe_ctx.GetTargetPtr();
 
     if (!m_options.symbol_name.empty()) {
Index: lldb/source/Commands/CommandObjectReproducer.cpp
===================================================================
--- lldb/source/Commands/CommandObjectReproducer.cpp
+++ lldb/source/Commands/CommandObjectReproducer.cpp
@@ -182,12 +182,6 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (!command.empty()) {
-      result.AppendErrorWithFormat("'%s' takes no arguments",
-                                   m_cmd_name.c_str());
-      return false;
-    }
-
     auto &r = Reproducer::Instance();
     if (auto generator = r.GetGenerator()) {
       generator->Keep();
@@ -260,12 +254,6 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (!command.empty()) {
-      result.AppendErrorWithFormat("'%s' takes no arguments",
-                                   m_cmd_name.c_str());
-      return false;
-    }
-
     auto &r = Reproducer::Instance();
 
     if (!r.IsCapturing()) {
@@ -309,12 +297,6 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (!command.empty()) {
-      result.AppendErrorWithFormat("'%s' takes no arguments",
-                                   m_cmd_name.c_str());
-      return false;
-    }
-
     auto &r = Reproducer::Instance();
     if (r.IsCapturing()) {
       result.GetOutputStream() << "Reproducer is in capture mode.\n";
@@ -394,12 +376,6 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (!command.empty()) {
-      result.AppendErrorWithFormat("'%s' takes no arguments",
-                                   m_cmd_name.c_str());
-      return false;
-    }
-
     llvm::Optional<Loader> loader_storage;
     Loader *loader =
         GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
Index: lldb/source/Commands/CommandObjectQuit.cpp
===================================================================
--- lldb/source/Commands/CommandObjectQuit.cpp
+++ lldb/source/Commands/CommandObjectQuit.cpp
@@ -20,7 +20,10 @@
 
 CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter)
     : CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.",
-                          "quit [exit-code]") {}
+                          "quit [exit-code]") {
+  CommandArgumentData exit_code_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+  m_arguments.push_back({exit_code_arg});
+}
 
 CommandObjectQuit::~CommandObjectQuit() = default;
 
Index: lldb/source/Commands/CommandObjectProcess.cpp
===================================================================
--- lldb/source/Commands/CommandObjectProcess.cpp
+++ lldb/source/Commands/CommandObjectProcess.cpp
@@ -414,12 +414,6 @@
     ModuleSP old_exec_module_sp = target->GetExecutableModule();
     ArchSpec old_arch_spec = target->GetArchitecture();
 
-    if (command.GetArgumentCount()) {
-      result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n",
-                                   m_cmd_name.c_str(), m_cmd_syntax.c_str());
-      return false;
-    }
-
     StreamString stream;
     ProcessSP process_sp;
     const auto error = target->Attach(m_options.attach_info, &stream);
@@ -562,13 +556,6 @@
     bool synchronous_execution = m_interpreter.GetSynchronous();
     StateType state = process->GetState();
     if (state == eStateStopped) {
-      if (command.GetArgumentCount() != 0) {
-        result.AppendErrorWithFormat(
-            "The '%s' command does not take any arguments.\n",
-            m_cmd_name.c_str());
-        return false;
-      }
-
       if (m_options.m_ignore > 0) {
         ThreadSP sel_thread_sp(GetDefaultThread()->shared_from_this());
         if (sel_thread_sp) {
@@ -943,7 +930,10 @@
   CommandObjectProcessConnect(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "process connect",
                             "Connect to a remote debug service.",
-                            "process connect <remote-url>", 0) {}
+                            "process connect <remote-url>", 0) {
+    CommandArgumentData connect_arg{eArgTypeConnectURL, eArgRepeatPlain};
+    m_arguments.push_back({connect_arg});
+  }
 
   ~CommandObjectProcessConnect() override = default;
 
@@ -1068,7 +1058,10 @@
                             "process load <filename> [<filename> ...]",
                             eCommandRequiresProcess | eCommandTryTargetAPILock |
                                 eCommandProcessMustBeLaunched |
-                                eCommandProcessMustBePaused) {}
+                                eCommandProcessMustBePaused) {
+    CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlus};
+    m_arguments.push_back({file_arg});
+  }
 
   ~CommandObjectProcessLoad() override = default;
 
@@ -1143,7 +1136,10 @@
             "returned by a previous call to \"process load\".",
             "process unload <index>",
             eCommandRequiresProcess | eCommandTryTargetAPILock |
-                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
+                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
+    CommandArgumentData load_idx_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    m_arguments.push_back({load_idx_arg});
+  }
 
   ~CommandObjectProcessUnload() override = default;
 
@@ -1291,18 +1287,13 @@
       return false;
     }
 
-    if (command.GetArgumentCount() == 0) {
-      bool clear_thread_plans = true;
-      Status error(process->Halt(clear_thread_plans));
-      if (error.Success()) {
-        result.SetStatus(eReturnStatusSuccessFinishResult);
-      } else {
-        result.AppendErrorWithFormat("Failed to halt process: %s\n",
-                                     error.AsCString());
-      }
+    bool clear_thread_plans = true;
+    Status error(process->Halt(clear_thread_plans));
+    if (error.Success()) {
+      result.SetStatus(eReturnStatusSuccessFinishResult);
     } else {
-      result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
-                                   m_cmd_name.c_str(), m_cmd_syntax.c_str());
+      result.AppendErrorWithFormat("Failed to halt process: %s\n",
+                                   error.AsCString());
     }
     return result.Succeeded();
   }
@@ -1330,17 +1321,12 @@
       return false;
     }
 
-    if (command.GetArgumentCount() == 0) {
-      Status error(process->Destroy(true));
-      if (error.Success()) {
-        result.SetStatus(eReturnStatusSuccessFinishResult);
-      } else {
-        result.AppendErrorWithFormat("Failed to kill process: %s\n",
-                                     error.AsCString());
-      }
+    Status error(process->Destroy(true));
+    if (error.Success()) {
+      result.SetStatus(eReturnStatusSuccessFinishResult);
     } else {
-      result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
-                                   m_cmd_name.c_str(), m_cmd_syntax.c_str());
+      result.AppendErrorWithFormat("Failed to kill process: %s\n",
+                                   error.AsCString());
     }
     return result.Succeeded();
   }
@@ -1372,7 +1358,10 @@
             "appropriate file type.",
             "process save-core [-s corefile-style -p plugin-name] FILE",
             eCommandRequiresProcess | eCommandTryTargetAPILock |
-                eCommandProcessMustBeLaunched) {}
+                eCommandProcessMustBeLaunched) {
+    CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlain};
+    m_arguments.push_back({file_arg});
+  }
 
   ~CommandObjectProcessSaveCore() override = default;
 
@@ -1519,11 +1508,6 @@
     Stream &strm = result.GetOutputStream();
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
 
-    if (command.GetArgumentCount()) {
-      result.AppendError("'process status' takes no arguments");
-      return result.Succeeded();
-    }
-
     // No need to check "process" for validity as eCommandRequiresProcess
     // ensures it is valid
     Process *process = m_exe_ctx.GetProcessPtr();
Index: lldb/source/Commands/CommandObjectPlatform.cpp
===================================================================
--- lldb/source/Commands/CommandObjectPlatform.cpp
+++ lldb/source/Commands/CommandObjectPlatform.cpp
@@ -150,6 +150,8 @@
   {
     m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
     m_option_group.Finalize();
+    CommandArgumentData platform_arg{eArgTypePlatform, eArgRepeatPlain};
+    m_arguments.push_back({platform_arg});
   }
 
   ~CommandObjectPlatformSelect() override = default;
@@ -271,7 +273,10 @@
       : CommandObjectParsed(
             interpreter, "platform connect",
             "Select the current platform by providing a connection URL.",
-            "platform connect <connect-url>", 0) {}
+            "platform connect <connect-url>", 0) {
+    CommandArgumentData platform_arg{eArgTypeConnectURL, eArgRepeatPlain};
+    m_arguments.push_back({platform_arg});
+  }
 
   ~CommandObjectPlatformConnect() override = default;
 
@@ -415,7 +420,10 @@
   CommandObjectPlatformMkDir(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "platform mkdir",
                             "Make a new directory on the remote end.", nullptr,
-                            0) {}
+                            0) {
+    CommandArgumentData thread_arg{eArgTypePath, eArgRepeatPlain};
+    m_arguments.push_back({thread_arg});
+  }
 
   ~CommandObjectPlatformMkDir() override = default;
 
@@ -461,7 +469,10 @@
 public:
   CommandObjectPlatformFOpen(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "platform file open",
-                            "Open a file on the remote end.", nullptr, 0) {}
+                            "Open a file on the remote end.", nullptr, 0) {
+    CommandArgumentData path_arg{eArgTypePath, eArgRepeatPlain};
+    m_arguments.push_back({path_arg});
+  }
 
   ~CommandObjectPlatformFOpen() override = default;
 
@@ -521,7 +532,10 @@
 public:
   CommandObjectPlatformFClose(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "platform file close",
-                            "Close a file on the remote end.", nullptr, 0) {}
+                            "Close a file on the remote end.", nullptr, 0) {
+    CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    m_arguments.push_back({path_arg});
+  }
 
   ~CommandObjectPlatformFClose() override = default;
 
@@ -562,7 +576,10 @@
   CommandObjectPlatformFRead(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "platform file read",
                             "Read data from a file on the remote end.", nullptr,
-                            0) {}
+                            0) {
+    CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    m_arguments.push_back({path_arg});
+  }
 
   ~CommandObjectPlatformFRead() override = default;
 
@@ -655,7 +672,10 @@
   CommandObjectPlatformFWrite(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "platform file write",
                             "Write data to a file on the remote end.", nullptr,
-                            0) {}
+                            0) {
+    CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
+    m_arguments.push_back({path_arg});
+  }
 
   ~CommandObjectPlatformFWrite() override = default;
 
@@ -1070,6 +1090,10 @@
     Relative source file paths are resolved against lldb's local working directory.
 
     Omitting the destination places the file in the platform working directory.)");
+    CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain};
+    CommandArgumentData path_arg{eArgTypePath, eArgRepeatOptional};
+    m_arguments.push_back({source_arg});
+    m_arguments.push_back({path_arg});
   }
 
   ~CommandObjectPlatformPutFile() override = default;
@@ -1121,6 +1145,8 @@
                             eCommandRequiresTarget | eCommandTryTargetAPILock) {
     m_all_options.Append(&m_options);
     m_all_options.Finalize();
+    CommandArgumentData run_arg_arg{eArgTypeRunArgs, eArgRepeatStar};
+    m_arguments.push_back({run_arg_arg});
   }
 
   ~CommandObjectPlatformProcessLaunch() override = default;
@@ -1229,83 +1255,78 @@
 
     if (platform_sp) {
       Status error;
-      if (args.GetArgumentCount() == 0) {
-        if (platform_sp) {
-          Stream &ostrm = result.GetOutputStream();
-
-          lldb::pid_t pid =
-              m_options.match_info.GetProcessInfo().GetProcessID();
-          if (pid != LLDB_INVALID_PROCESS_ID) {
-            ProcessInstanceInfo proc_info;
-            if (platform_sp->GetProcessInfo(pid, proc_info)) {
-              ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
-                                                   m_options.verbose);
-              proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
-                                       m_options.show_args, m_options.verbose);
-              result.SetStatus(eReturnStatusSuccessFinishResult);
-            } else {
-              result.AppendErrorWithFormat(
-                  "no process found with pid = %" PRIu64 "\n", pid);
-            }
+      if (platform_sp) {
+        Stream &ostrm = result.GetOutputStream();
+
+        lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
+        if (pid != LLDB_INVALID_PROCESS_ID) {
+          ProcessInstanceInfo proc_info;
+          if (platform_sp->GetProcessInfo(pid, proc_info)) {
+            ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
+                                                 m_options.verbose);
+            proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
+                                     m_options.show_args, m_options.verbose);
+            result.SetStatus(eReturnStatusSuccessFinishResult);
           } else {
-            ProcessInstanceInfoList proc_infos;
-            const uint32_t matches =
-                platform_sp->FindProcesses(m_options.match_info, proc_infos);
-            const char *match_desc = nullptr;
-            const char *match_name =
-                m_options.match_info.GetProcessInfo().GetName();
-            if (match_name && match_name[0]) {
-              switch (m_options.match_info.GetNameMatchType()) {
-              case NameMatch::Ignore:
-                break;
-              case NameMatch::Equals:
-                match_desc = "matched";
-                break;
-              case NameMatch::Contains:
-                match_desc = "contained";
-                break;
-              case NameMatch::StartsWith:
-                match_desc = "started with";
-                break;
-              case NameMatch::EndsWith:
-                match_desc = "ended with";
-                break;
-              case NameMatch::RegularExpression:
-                match_desc = "matched the regular expression";
-                break;
-              }
+            result.AppendErrorWithFormat(
+                "no process found with pid = %" PRIu64 "\n", pid);
+          }
+        } else {
+          ProcessInstanceInfoList proc_infos;
+          const uint32_t matches =
+              platform_sp->FindProcesses(m_options.match_info, proc_infos);
+          const char *match_desc = nullptr;
+          const char *match_name =
+              m_options.match_info.GetProcessInfo().GetName();
+          if (match_name && match_name[0]) {
+            switch (m_options.match_info.GetNameMatchType()) {
+            case NameMatch::Ignore:
+              break;
+            case NameMatch::Equals:
+              match_desc = "matched";
+              break;
+            case NameMatch::Contains:
+              match_desc = "contained";
+              break;
+            case NameMatch::StartsWith:
+              match_desc = "started with";
+              break;
+            case NameMatch::EndsWith:
+              match_desc = "ended with";
+              break;
+            case NameMatch::RegularExpression:
+              match_desc = "matched the regular expression";
+              break;
             }
+          }
 
-            if (matches == 0) {
-              if (match_desc)
-                result.AppendErrorWithFormatv(
-                    "no processes were found that {0} \"{1}\" on the \"{2}\" "
-                    "platform\n",
-                    match_desc, match_name, platform_sp->GetName());
-              else
-                result.AppendErrorWithFormatv(
-                    "no processes were found on the \"{0}\" platform\n",
-                    platform_sp->GetName());
-            } else {
-              result.AppendMessageWithFormatv(
-                  "{0} matching process{1} found on \"{2}\"", matches,
-                  matches > 1 ? "es were" : " was", platform_sp->GetName());
-              if (match_desc)
-                result.AppendMessageWithFormat(" whose name %s \"%s\"",
-                                               match_desc, match_name);
-              result.AppendMessageWithFormat("\n");
-              ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
-                                                   m_options.verbose);
-              for (uint32_t i = 0; i < matches; ++i) {
-                proc_infos[i].DumpAsTableRow(
-                    ostrm, platform_sp->GetUserIDResolver(),
-                    m_options.show_args, m_options.verbose);
-              }
+          if (matches == 0) {
+            if (match_desc)
+              result.AppendErrorWithFormatv(
+                  "no processes were found that {0} \"{1}\" on the \"{2}\" "
+                  "platform\n",
+                  match_desc, match_name, platform_sp->GetName());
+            else
+              result.AppendErrorWithFormatv(
+                  "no processes were found on the \"{0}\" platform\n",
+                  platform_sp->GetName());
+          } else {
+            result.AppendMessageWithFormatv(
+                "{0} matching process{1} found on \"{2}\"", matches,
+                matches > 1 ? "es were" : " was", platform_sp->GetName());
+            if (match_desc)
+              result.AppendMessageWithFormat(" whose name %s \"%s\"",
+                                             match_desc, match_name);
+            result.AppendMessageWithFormat("\n");
+            ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
+                                                 m_options.verbose);
+            for (uint32_t i = 0; i < matches; ++i) {
+              proc_infos[i].DumpAsTableRow(
+                  ostrm, platform_sp->GetUserIDResolver(), m_options.show_args,
+                  m_options.verbose);
             }
           }
         }
-      } else {
-        result.AppendError("invalid args: process list takes only options\n");
       }
     } else {
       result.AppendError("no platform is selected\n");
@@ -1737,7 +1758,10 @@
   CommandObjectPlatformShell(CommandInterpreter &interpreter)
       : CommandObjectRaw(interpreter, "platform shell",
                          "Run a shell command on the current platform.",
-                         "platform shell <shell-command>", 0) {}
+                         "platform shell <shell-command>", 0) {
+    CommandArgumentData thread_arg{eArgTypeNone, eArgRepeatStar};
+    m_arguments.push_back({thread_arg});
+  }
 
   ~CommandObjectPlatformShell() override = default;
 
@@ -1824,7 +1848,12 @@
       : CommandObjectParsed(
             interpreter, "platform target-install",
             "Install a target (bundle or executable file) to the remote end.",
-            "platform target-install <local-thing> <remote-sandbox>", 0) {}
+            "platform target-install <local-thing> <remote-sandbox>", 0) {
+    CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain};
+    CommandArgumentData remote_arg{eArgTypePath, eArgRepeatPlain};
+    m_arguments.push_back({local_arg});
+    m_arguments.push_back({remote_arg});
+  }
 
   ~CommandObjectPlatformInstall() override = default;
 
Index: lldb/source/Commands/CommandObjectGUI.cpp
===================================================================
--- lldb/source/Commands/CommandObjectGUI.cpp
+++ lldb/source/Commands/CommandObjectGUI.cpp
@@ -26,22 +26,18 @@
 
 bool CommandObjectGUI::DoExecute(Args &args, CommandReturnObject &result) {
 #if LLDB_ENABLE_CURSES
-  if (args.GetArgumentCount() == 0) {
-    Debugger &debugger = GetDebugger();
-
-    File &input = debugger.GetInputFile();
-    File &output = debugger.GetOutputFile();
-    if (input.GetStream() && output.GetStream() && input.GetIsRealTerminal() &&
-        input.GetIsInteractive()) {
-      IOHandlerSP io_handler_sp(new IOHandlerCursesGUI(debugger));
-      if (io_handler_sp)
-        debugger.RunIOHandlerAsync(io_handler_sp);
-      result.SetStatus(eReturnStatusSuccessFinishResult);
-    } else {
-      result.AppendError("the gui command requires an interactive terminal.");
-    }
+  Debugger &debugger = GetDebugger();
+
+  File &input = debugger.GetInputFile();
+  File &output = debugger.GetOutputFile();
+  if (input.GetStream() && output.GetStream() && input.GetIsRealTerminal() &&
+      input.GetIsInteractive()) {
+    IOHandlerSP io_handler_sp(new IOHandlerCursesGUI(debugger));
+    if (io_handler_sp)
+      debugger.RunIOHandlerAsync(io_handler_sp);
+    result.SetStatus(eReturnStatusSuccessFinishResult);
   } else {
-    result.AppendError("the gui command takes no arguments.");
+    result.AppendError("the gui command requires an interactive terminal.");
   }
   return true;
 #else
Index: lldb/source/Commands/CommandObjectFrame.cpp
===================================================================
--- lldb/source/Commands/CommandObjectFrame.cpp
+++ lldb/source/Commands/CommandObjectFrame.cpp
@@ -924,7 +924,11 @@
 public:
   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
       : CommandObjectParsed(interpreter, "frame recognizer delete",
-                            "Delete an existing frame recognizer.", nullptr) {}
+                            "Delete an existing frame recognizer by id.",
+                            nullptr) {
+    CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain};
+    m_arguments.push_back({thread_arg});
+  }
 
   ~CommandObjectFrameRecognizerDelete() override = default;
 
Index: lldb/source/Commands/CommandObjectCommands.cpp
===================================================================
--- lldb/source/Commands/CommandObjectCommands.cpp
+++ lldb/source/Commands/CommandObjectCommands.cpp
@@ -824,6 +824,8 @@
         R"(
 
     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
+    CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional};
+    m_arguments.push_back({thread_arg});
   }
 
   ~CommandObjectCommandsAddRegex() override = default;
@@ -1664,11 +1666,6 @@
   ~CommandObjectCommandsScriptList() override = default;
 
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (command.GetArgumentCount() != 0) {
-      result.AppendError("'command script list' doesn't take any arguments");
-      return false;
-    }
-
     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
 
     result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -1689,11 +1686,6 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (command.GetArgumentCount() != 0) {
-      result.AppendError("'command script clear' doesn't take any arguments");
-      return false;
-    }
-
     m_interpreter.RemoveAllUser();
 
     result.SetStatus(eReturnStatusSuccessFinishResult);
Index: lldb/source/API/SBCommandInterpreter.cpp
===================================================================
--- lldb/source/API/SBCommandInterpreter.cpp
+++ lldb/source/API/SBCommandInterpreter.cpp
@@ -47,6 +47,10 @@
         auto_repeat_command == nullptr
             ? llvm::None
             : llvm::Optional<std::string>(auto_repeat_command);
+    // We don't know whether any given command coming from this interface takes
+    // arguments or not so here we're just disabling the basic args check.
+    CommandArgumentData none_arg{eArgTypeNone, eArgRepeatStar};
+    m_arguments.push_back({none_arg});
   }
 
   bool IsRemovable() const override { return true; }
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -602,6 +602,11 @@
   eArgTypeColumnNum,
   eArgTypeModuleUUID,
   eArgTypeSaveCoreStyle,
+  eArgTypeSEDStylePair,
+  eArgTypeRecognizerID,
+  eArgTypeConnectURL,
+  eArgTypeTargetID,
+  eArgTypeStopHookID,
   eArgTypeLastArg // Always keep this entry as the last entry in this
                   // enumeration!!
 };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to