jingham created this revision.
jingham added reviewers: clayborg, teemperor.
Herald added subscribers: lldb-commits, JDevlieghere, abidh, mgorny.
Herald added a project: LLDB.

I want to reuse these options (break set's -P -k -v) in another command (thread 
step-scripted) in a future commit, so I broke them off into their own 
OptionGroup.  I made the short options settable because you can never tell 
whether there's going to be the same three open slots in every command.  For 
instance, "thread step-scripted" uses -C not -P, which will be more correct 
if/when we have another script interpreter.  But -C was already taken for 
"break set"...

I added some tests for the parsing of these options.  In the course of adding 
those tests I discovered that if an OptionGroup returns an error, and the 
option is not the last option in the line, the error is ignored.  I fixed that 
as well - that's the change to Options.cpp


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D68363

Files:
  
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py
  
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py
  lldb/source/Commands/CommandObjectBreakpoint.cpp
  lldb/source/Commands/Options.td
  lldb/source/Interpreter/CMakeLists.txt
  lldb/source/Interpreter/Options.cpp

Index: lldb/source/Interpreter/Options.cpp
===================================================================
--- lldb/source/Interpreter/Options.cpp
+++ lldb/source/Interpreter/Options.cpp
@@ -1380,6 +1380,10 @@
                                ? nullptr
                                : OptionParser::GetOptionArgument(),
                            execution_context);
+      // If the Option setting returned an error, we should stop parsing
+      // and return the error.
+      if (error.Fail())
+        break;      
     } else {
       error.SetErrorStringWithFormat("invalid option with value '%i'", val);
     }
Index: lldb/source/Interpreter/CMakeLists.txt
===================================================================
--- lldb/source/Interpreter/CMakeLists.txt
+++ lldb/source/Interpreter/CMakeLists.txt
@@ -20,6 +20,7 @@
   OptionGroupBoolean.cpp
   OptionGroupFile.cpp
   OptionGroupFormat.cpp
+  OptionGroupPythonClassWithDict.cpp
   OptionGroupOutputFile.cpp
   OptionGroupPlatform.cpp
   OptionGroupString.cpp
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -163,17 +163,6 @@
     "match against all source files, pass the \"--all-files\" option.">;
   def breakpoint_set_all_files : Option<"all-files", "A">, Group<9>,
     Desc<"All files are searched for source pattern matches.">;
-  def breakpoint_set_python_class : Option<"python-class", "P">, Group<11>,
-    Arg<"PythonClass">, Required, Desc<"The name of the class that implement "
-    "a scripted breakpoint.">;
-  def breakpoint_set_python_class_key : Option<"python-class-key", "k">,
-    Group<11>, Arg<"None">,
-    Desc<"The key for a key/value pair passed to the class that implements a "
-    "scripted breakpoint.  Can be specified more than once.">;
-  def breakpoint_set_python_class_value : Option<"python-class-value", "v">,
-    Group<11>, Arg<"None">, Desc<"The value for the previous key in the pair "
-    "passed to the class that implements a scripted breakpoint. "
-    "Can be specified more than once.">;
   def breakpoint_set_language_exception : Option<"language-exception", "E">,
     Group<10>, Arg<"Language">, Required,
     Desc<"Set the breakpoint on exceptions thrown by the specified language "
Index: lldb/source/Commands/CommandObjectBreakpoint.cpp
===================================================================
--- lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
 #include "lldb/Interpreter/OptionValueBoolean.h"
 #include "lldb/Interpreter/OptionValueString.h"
 #include "lldb/Interpreter/OptionValueUInt64.h"
@@ -241,12 +242,16 @@
             interpreter, "breakpoint set",
             "Sets a breakpoint or set of breakpoints in the executable.",
             "breakpoint set <cmd-options>"),
+        m_python_class_options("scripted breakpoint", 'P'),
         m_bp_opts(), m_options() {
           // We're picking up all the normal options, commands and disable.
+          m_all_options.Append(&m_python_class_options, LLDB_OPT_SET_1,
+                               LLDB_OPT_SET_11);
           m_all_options.Append(&m_bp_opts, 
                                LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4, 
                                LLDB_OPT_SET_ALL);
-          m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
+          m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, 
+                               LLDB_OPT_SET_ALL);
           m_all_options.Append(&m_options);
           m_all_options.Finalize();
         }
@@ -352,14 +357,6 @@
         m_hardware = true;
         break;
         
-      case 'k': {
-          if (m_current_key.empty())
-            m_current_key.assign(option_arg);
-          else
-            error.SetErrorStringWithFormat("Key: %s missing value.",
-                                            m_current_key.c_str());
-        
-      } break;
       case 'K': {
         bool success;
         bool value;
@@ -441,10 +438,6 @@
         m_source_text_regexp.assign(option_arg);
         break;
         
-      case 'P':
-        m_python_class.assign(option_arg);
-        break;
-
       case 'r':
         m_func_regexp.assign(option_arg);
         break;
@@ -458,16 +451,6 @@
         m_func_name_type_mask |= eFunctionNameTypeSelector;
         break;
 
-      case 'v': {
-          if (!m_current_key.empty()) {
-              m_extra_args_sp->AddStringItem(m_current_key, option_arg);
-              m_current_key.clear();
-          }
-          else
-            error.SetErrorStringWithFormat("Value \"%s\" missing matching key.",
-                                           option_arg.str().c_str());
-      } break;
-        
       case 'w': {
         bool success;
         m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
@@ -510,8 +493,6 @@
       m_exception_extra_args.Clear();
       m_move_to_nearest_code = eLazyBoolCalculate;
       m_source_regex_func_names.clear();
-      m_python_class.clear();
-      m_extra_args_sp = std::make_shared<StructuredData::Dictionary>();
       m_current_key.clear();
     }
 
@@ -543,8 +524,6 @@
     Args m_exception_extra_args;
     LazyBool m_move_to_nearest_code;
     std::unordered_set<std::string> m_source_regex_func_names;
-    std::string m_python_class;
-    StructuredData::DictionarySP m_extra_args_sp;
     std::string m_current_key;
   };
 
@@ -565,7 +544,7 @@
 
     BreakpointSetType break_type = eSetTypeInvalid;
 
-    if (!m_options.m_python_class.empty())
+    if (!m_python_class_options.GetClassName().empty())
       break_type = eSetTypeScripted;
     else if (m_options.m_line_num != 0)
       break_type = eSetTypeFileAndLine;
@@ -721,9 +700,9 @@
 
       Status error;
       bp_sp = target.CreateScriptedBreakpoint(
-          m_options.m_python_class, &(m_options.m_modules),
+          m_python_class_options.GetClassName().c_str(), &(m_options.m_modules),
           &(m_options.m_filenames), false, m_options.m_hardware,
-          m_options.m_extra_args_sp, &error);
+          m_python_class_options.GetStructuredData(), &error);
       if (error.Fail()) {
         result.AppendErrorWithFormat(
             "Error setting extra exception arguments: %s",
@@ -818,6 +797,7 @@
 
   BreakpointOptionGroup m_bp_opts;
   BreakpointDummyOptionGroup m_dummy_options;
+  OptionGroupPythonClassWithDict m_python_class_options;
   CommandOptions m_options;
   OptionGroupOptions m_all_options;
 };
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py
@@ -7,6 +7,7 @@
   def __init__(self, bkpt, extra_args, dict):
       self.bkpt = bkpt
       self.extra_args = extra_args
+        
       Resolver.func_list = []
       Resolver.got_files = 0
 
@@ -15,6 +16,8 @@
       sym_item = self.extra_args.GetValueForKey("symbol")
       if sym_item.IsValid():
           sym_name = sym_item.GetStringValue(1000)
+      else:
+          print("Didn't have a value for key 'symbol'")
 
       if sym_ctx.compile_unit.IsValid():
           Resolver.got_files = 1
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py
@@ -38,6 +38,12 @@
         self.build()
         self.do_test_cli()
 
+    def test_bad_command_lines(self):
+        """Make sure we get appropriate errors when we give invalid key/value
+           options"""
+        self.build()
+        self.do_test_bad_options()        
+
     def setUp(self):
         # Call super's setUp().
         TestBase.setUp(self)
@@ -195,3 +201,15 @@
         target = self.make_target_and_import()
 
         lldbutil.run_break_set_by_script(self, "resolver.Resolver", extra_options="-k symbol -v break_on_me")
+
+    def do_test_bad_options(self):
+        target = self.make_target_and_import()
+
+        self.expect("break set -P resolver.Resolver -k a_key", error = True, msg="Missing value at end", 
+           substrs=['Key: "a_key" missing value'])
+        self.expect("break set -P resolver.Resolver -v a_value", error = True, msg="Missing key at end", 
+           substrs=['Value: "a_value" missing matching key'])
+        self.expect("break set -P resolver.Resolver -v a_value -k a_key -v another_value", error = True, msg="Missing key among args", 
+           substrs=['Value: "a_value" missing matching key'])
+        self.expect("break set -P resolver.Resolver -k a_key -k a_key -v another_value", error = True, msg="Missing value among args", 
+           substrs=['Key: "a_key" missing value'])
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D68363:... Jim Ingham via Phabricator via lldb-commits

Reply via email to