diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.h b/lldb/source/Commands/CommandObjectDWIMPrint.h --- a/lldb/source/Commands/CommandObjectDWIMPrint.h +++ b/lldb/source/Commands/CommandObjectDWIMPrint.h @@ -10,6 +10,9 @@ #define LLDB_SOURCE_COMMANDS_COMMANDOBJECTDWIMPRINT_H #include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" +#include "lldb/Interpreter/OptionValueFormat.h" namespace lldb_private { @@ -31,8 +34,14 @@ ~CommandObjectDWIMPrint() override = default; + Options *GetOptions() override; + private: bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; + + OptionGroupOptions m_option_group; + OptionGroupFormat m_format_options = lldb::eFormatDefault; + OptionGroupValueObjectDisplay m_varobj_options; }; } // namespace lldb_private diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp --- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp +++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp @@ -9,13 +9,19 @@ #include "CommandObjectDWIMPrint.h" #include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/DumpValueObjectOptions.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" #include "lldb/Target/StackFrame.h" #include "lldb/Utility/ConstString.h" +#include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" using namespace llvm; using namespace lldb; @@ -26,28 +32,49 @@ "Print a variable or expression.", "dwim-print [ | ]", eCommandProcessMustBePaused | eCommandTryTargetAPILock) { + m_option_group.Append(&m_format_options, + OptionGroupFormat::OPTION_GROUP_FORMAT | + OptionGroupFormat::OPTION_GROUP_GDB_FMT, + LLDB_OPT_SET_1); + m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Finalize(); } -bool CommandObjectDWIMPrint::DoExecute(StringRef expr, - CommandReturnObject &result) { - // Ignore leading and trailing whitespace. - expr = expr.trim(); +Options *CommandObjectDWIMPrint::GetOptions() { return &m_option_group; } - if (expr.empty()) { +bool CommandObjectDWIMPrint::DoExecute(StringRef command, + CommandReturnObject &result) { + m_option_group.NotifyOptionParsingStarting(&m_exe_ctx); + OptionsWithRaw args{command}; + StringRef expr = args.GetRawPart(); + + if (args.HasArgs()) { + if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, + m_exe_ctx)) + return false; + } else if (command.empty()) { result.AppendErrorWithFormatv("'{0}' takes a variable or expression", m_cmd_name); return false; } - auto verbosity = GetDebugger().GetDWIMPrintVerbosity(); + DumpValueObjectOptions dump_options = m_varobj_options.GetAsDumpOptions( + eLanguageRuntimeDescriptionDisplayVerbosityFull, + m_format_options.GetFormat()); + // First, try `expr` as the name of a frame variable. if (StackFrame *frame = m_exe_ctx.GetFramePtr()) { auto valobj_sp = frame->FindVariable(ConstString(expr)); if (valobj_sp && valobj_sp->GetError().Success()) { - if (verbosity == eDWIMPrintVerbosityFull) - result.AppendMessageWithFormatv("note: ran `frame variable {0}`", expr); - valobj_sp->Dump(result.GetOutputStream()); + if (verbosity == eDWIMPrintVerbosityFull) { + StringRef flags; + if (args.HasArgs()) + flags = args.GetArgString(); + result.AppendMessageWithFormatv("note: ran `frame variable {0}{1}`", + flags, expr); + } + valobj_sp->Dump(result.GetOutputStream(), dump_options); result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -63,9 +90,14 @@ ValueObjectSP valobj_sp; if (target.EvaluateExpression(expr, exe_scope, valobj_sp) == eExpressionCompleted) { - if (verbosity != eDWIMPrintVerbosityNone) - result.AppendMessageWithFormatv("note: ran `expression -- {0}`", expr); - valobj_sp->Dump(result.GetOutputStream()); + if (verbosity != eDWIMPrintVerbosityNone) { + StringRef flags; + if (args.HasArgs()) + flags = args.GetArgStringWithDelimiter(); + result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags, + expr); + } + valobj_sp->Dump(result.GetOutputStream(), dump_options); result.SetStatus(eReturnStatusSuccessFinishResult); return true; } else { diff --git a/lldb/source/Interpreter/OptionGroupFormat.cpp b/lldb/source/Interpreter/OptionGroupFormat.cpp --- a/lldb/source/Interpreter/OptionGroupFormat.cpp +++ b/lldb/source/Interpreter/OptionGroupFormat.cpp @@ -12,6 +12,7 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" +#include "lldb/lldb-enumerations.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/test/API/commands/dwim-print/TestDWIMPrint.py b/lldb/test/API/commands/dwim-print/TestDWIMPrint.py --- a/lldb/test/API/commands/dwim-print/TestDWIMPrint.py +++ b/lldb/test/API/commands/dwim-print/TestDWIMPrint.py @@ -27,22 +27,37 @@ before, after = self.PERSISTENT_VAR.split(string, maxsplit=1) return re.escape(before) + r"\$\d+" + re.escape(after) - def _expect_cmd(self, expr: str, base_cmd: str) -> None: + def _expect_cmd( + self, + dwim_cmd: str, + actual_cmd: str, + ) -> None: """Run dwim-print and verify the output against the expected command.""" - cmd = f"{base_cmd} {expr}" - cmd_output = self._run_cmd(cmd) + # Resolve the dwim-print command to either `expression` or `frame variable`. + substitute_cmd = dwim_cmd.replace("dwim-print", actual_cmd, 1) + interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + interp.ResolveCommand(substitute_cmd, result) + if not result.Succeeded(): + raise RuntimeError(result.GetError()) + + resolved_cmd = result.GetOutput() + if actual_cmd == "frame variable": + resolved_cmd = resolved_cmd.replace(" -- ", " ", 1) + + expected_output = self._run_cmd(resolved_cmd) # Verify dwim-print chose the expected command. self.runCmd("settings set dwim-print-verbosity full") - substrs = [f"note: ran `{cmd}`"] + substrs = [f"note: ran `{resolved_cmd}`"] patterns = [] - if base_cmd == "expression --" and self.PERSISTENT_VAR.search(cmd_output): - patterns.append(self._mask_persistent_var(cmd_output)) + if actual_cmd == "expression" and self.PERSISTENT_VAR.search(expected_output): + patterns.append(self._mask_persistent_var(expected_output)) else: - substrs.append(cmd_output) + substrs.append(expected_output) - self.expect(f"dwim-print {expr}", substrs=substrs, patterns=patterns) + self.expect(dwim_cmd, substrs=substrs, patterns=patterns) def test_variables(self): """Test dwim-print with variables.""" @@ -50,7 +65,7 @@ lldbutil.run_to_name_breakpoint(self, "main") vars = ("argc", "argv") for var in vars: - self._expect_cmd(var, "frame variable") + self._expect_cmd(f"dwim-print {var}", "frame variable") def test_variable_paths(self): """Test dwim-print with variable path expressions.""" @@ -58,7 +73,7 @@ lldbutil.run_to_name_breakpoint(self, "main") exprs = ("&argc", "*argv", "argv[0]") for expr in exprs: - self._expect_cmd(expr, "expression --") + self._expect_cmd(f"dwim-print {expr}", "expression") def test_expressions(self): """Test dwim-print with expressions.""" @@ -66,8 +81,20 @@ lldbutil.run_to_name_breakpoint(self, "main") exprs = ("argc + 1", "(void)argc", "(int)abs(argc)") for expr in exprs: - self._expect_cmd(expr, "expression --") + self._expect_cmd(f"dwim-print {expr}", "expression") def test_dummy_target_expressions(self): """Test dwim-print's ability to evaluate expressions without a target.""" - self._expect_cmd("1 + 2", "expression --") + self._expect_cmd("dwim-print 1 + 2", "expression") + + def test_gdb_format(self): + self.build() + lldbutil.run_to_name_breakpoint(self, "main") + self._expect_cmd(f"dwim-print/x argc", "frame variable") + self._expect_cmd(f"dwim-print/x argc + 1", "expression") + + def test_flags(self): + self.build() + lldbutil.run_to_name_breakpoint(self, "main") + self._expect_cmd(f"dwim-print -fx -- argc", "frame variable") + self._expect_cmd(f"dwim-print -fx -- argc + 1", "expression")