This revision was automatically updated to reflect the committed changes.
Closed by commit rG185d4964a158: [lldb] Introduce dwim-print command (authored 
by kastiglione).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D138315/new/

https://reviews.llvm.org/D138315

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/lldb-enumerations.h
  lldb/source/Commands/CMakeLists.txt
  lldb/source/Commands/CommandObjectDWIMPrint.cpp
  lldb/source/Commands/CommandObjectDWIMPrint.h
  lldb/source/Core/CoreProperties.td
  lldb/source/Core/Debugger.cpp
  lldb/source/Interpreter/CommandInterpreter.cpp
  lldb/test/API/commands/dwim-print/Makefile
  lldb/test/API/commands/dwim-print/TestDWIMPrint.py
  lldb/test/API/commands/dwim-print/main.c

Index: lldb/test/API/commands/dwim-print/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/commands/dwim-print/main.c
@@ -0,0 +1,3 @@
+int main(int argc, char **argv) {
+  return 0;
+}
Index: lldb/test/API/commands/dwim-print/TestDWIMPrint.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/dwim-print/TestDWIMPrint.py
@@ -0,0 +1,68 @@
+"""
+Test dwim-print with variables, variable paths, and expressions.
+"""
+
+import re
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class TestCase(TestBase):
+    def setUp(self):
+        TestBase.setUp(self)
+        self.build()
+        lldbutil.run_to_name_breakpoint(self, "main")
+
+    def _run_cmd(self, cmd: str) -> str:
+        """Run the given lldb command and return its output."""
+        result = lldb.SBCommandReturnObject()
+        self.ci.HandleCommand(cmd, result)
+        return result.GetOutput().rstrip()
+
+    PERSISTENT_VAR = re.compile(r"\$\d+")
+
+    def _mask_persistent_var(self, string: str) -> str:
+        """
+        Replace persistent result variables (ex '$0', '$1', etc) with a regex
+        that matches any persistent result (r'\$\d+'). The returned string can
+        be matched against other `expression` results.
+        """
+        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:
+        """Run dwim-print and verify the output against the expected command."""
+        cmd = f"{base_cmd} {expr}"
+        cmd_output = self._run_cmd(cmd)
+
+        # Verify dwim-print chose the expected command.
+        self.runCmd("settings set dwim-print-verbosity full")
+        substrs = [f"note: ran `{cmd}`"]
+        patterns = []
+
+        if base_cmd == "expression --" and self.PERSISTENT_VAR.search(cmd_output):
+            patterns.append(self._mask_persistent_var(cmd_output))
+        else:
+            substrs.append(cmd_output)
+
+        self.expect(f"dwim-print {expr}", substrs=substrs, patterns=patterns)
+
+    def test_variables(self):
+        """Test dwim-print with variables."""
+        vars = ("argc", "argv")
+        for var in vars:
+            self._expect_cmd(var, "frame variable")
+
+    def test_variable_paths(self):
+        """Test dwim-print with variable path expressions."""
+        exprs = ("&argc", "*argv", "argv[0]")
+        for expr in exprs:
+            self._expect_cmd(expr, "expression --")
+
+    def test_expressions(self):
+        """Test dwim-print with expressions."""
+        exprs = ("argc + 1", "(void)argc", "(int)abs(argc)")
+        for expr in exprs:
+            self._expect_cmd(expr, "expression --")
Index: lldb/test/API/commands/dwim-print/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/commands/dwim-print/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/source/Interpreter/CommandInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/CommandInterpreter.cpp
+++ lldb/source/Interpreter/CommandInterpreter.cpp
@@ -15,6 +15,7 @@
 #include "Commands/CommandObjectApropos.h"
 #include "Commands/CommandObjectBreakpoint.h"
 #include "Commands/CommandObjectCommands.h"
+#include "Commands/CommandObjectDWIMPrint.h"
 #include "Commands/CommandObjectDiagnostics.h"
 #include "Commands/CommandObjectDisassemble.h"
 #include "Commands/CommandObjectExpression.h"
@@ -532,6 +533,7 @@
   REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
   REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
   REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
+  REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint);
   REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
   REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);
   REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI);
Index: lldb/source/Core/Debugger.cpp
===================================================================
--- lldb/source/Core/Debugger.cpp
+++ lldb/source/Core/Debugger.cpp
@@ -52,6 +52,7 @@
 #include "lldb/Utility/State.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-enumerations.h"
 
 #if defined(_WIN32)
 #include "lldb/Host/windows/PosixApi.h"
@@ -149,6 +150,16 @@
     },
 };
 
+static constexpr OptionEnumValueElement g_dwim_print_verbosities[] = {
+    {eDWIMPrintVerbosityNone, "none",
+     "Use no verbosity when running dwim-print."},
+    {eDWIMPrintVerbosityExpression, "expression",
+     "Use partial verbosity when running dwim-print - display a message when "
+     "`expression` evaluation is used."},
+    {eDWIMPrintVerbosityFull, "full",
+     "Use full verbosity when running dwim-print."},
+};
+
 static constexpr OptionEnumValueElement s_stop_show_column_values[] = {
     {
         eStopShowColumnAnsiOrCaret,
@@ -520,6 +531,13 @@
   return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size);
 }
 
+lldb::DWIMPrintVerbosity Debugger::GetDWIMPrintVerbosity() const {
+  const uint32_t idx = ePropertyDWIMPrintVerbosity;
+  return (lldb::DWIMPrintVerbosity)
+      m_collection_sp->GetPropertyAtIndexAsEnumeration(
+          nullptr, idx, g_debugger_properties[idx].default_uint_value);
+}
+
 #pragma mark Debugger
 
 // const DebuggerPropertiesSP &
Index: lldb/source/Core/CoreProperties.td
===================================================================
--- lldb/source/Core/CoreProperties.td
+++ lldb/source/Core/CoreProperties.td
@@ -191,4 +191,9 @@
     Global,
     DefaultStringValue<"${ansi.normal}">,
     Desc<"When displaying suggestion in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the suggestion.">;
+  def DWIMPrintVerbosity: Property<"dwim-print-verbosity", "Enum">,
+    Global,
+    DefaultEnumValue<"eDWIMPrintVerbosityExpression">,
+    EnumValues<"OptionEnumValues(g_dwim_print_verbosities)">,
+    Desc<"The verbosity level used by dwim-print.">;
 }
Index: lldb/source/Commands/CommandObjectDWIMPrint.h
===================================================================
--- /dev/null
+++ lldb/source/Commands/CommandObjectDWIMPrint.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectDWIMPrint.h --------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTDWIMPRINT_H
+#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTDWIMPRINT_H
+
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+/// Implements `dwim-print`, a printing command that chooses the most direct,
+/// efficient, and resilient means of printing a given expression.
+///
+/// DWIM is an acronym for Do What I Mean. From Wikipedia, DWIM is described as:
+///
+///   > attempt to anticipate what users intend to do, correcting trivial errors
+///   > automatically rather than blindly executing users' explicit but
+///   > potentially incorrect input
+///
+/// The `dwim-print` command serves as a single print command for users who
+/// don't yet know, or perfer not to know, the various lldb commands that can be
+/// used to print, and when to use them.
+class CommandObjectDWIMPrint : public CommandObjectRaw {
+public:
+  CommandObjectDWIMPrint(CommandInterpreter &interpreter);
+
+  ~CommandObjectDWIMPrint() override = default;
+
+private:
+  bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override;
+};
+
+} // namespace lldb_private
+
+#endif
Index: lldb/source/Commands/CommandObjectDWIMPrint.cpp
===================================================================
--- /dev/null
+++ lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -0,0 +1,84 @@
+//===-- CommandObjectDWIMPrint.cpp ------------------------------*- C++ -*-===//
+//
+// 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 "CommandObjectDWIMPrint.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter)
+    : CommandObjectRaw(
+          interpreter, "dwim-print", "Print a variable or expression.",
+          "dwim-print [<variable-name> | <expression>]",
+          eCommandProcessMustBePaused | eCommandTryTargetAPILock |
+              eCommandRequiresFrame | eCommandProcessMustBeLaunched |
+              eCommandRequiresProcess) {}
+
+bool CommandObjectDWIMPrint::DoExecute(StringRef expr,
+                                       CommandReturnObject &result) {
+  // Ignore leading and trailing whitespace.
+  expr = expr.trim();
+
+  if (expr.empty()) {
+    result.AppendErrorWithFormatv("'{0}' takes a variable or expression",
+                                  m_cmd_name);
+    return false;
+  }
+
+  // eCommandRequiresFrame guarantees a frame.
+  StackFrame *frame = m_exe_ctx.GetFramePtr();
+  assert(frame);
+
+  auto verbosity = GetDebugger().GetDWIMPrintVerbosity();
+
+  // First, try `expr` as the name of a variable.
+  {
+    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());
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+      return true;
+    }
+  }
+
+  // Second, also lastly, try `expr` as a source expression to evaluate.
+  {
+    // eCommandRequiresProcess guarantees a target.
+    Target *target = m_exe_ctx.GetTargetPtr();
+    assert(target);
+
+    ValueObjectSP valobj_sp;
+    if (target->EvaluateExpression(expr, frame, valobj_sp) ==
+        eExpressionCompleted) {
+      if (verbosity != eDWIMPrintVerbosityNone)
+        result.AppendMessageWithFormatv("note: ran `expression -- {0}`", expr);
+      valobj_sp->Dump(result.GetOutputStream());
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+      return true;
+    } else {
+      if (valobj_sp)
+        result.SetError(valobj_sp->GetError());
+      else
+        result.AppendErrorWithFormatv(
+            "unknown error evaluating expression `{0}`", expr);
+      return false;
+    }
+  }
+}
Index: lldb/source/Commands/CMakeLists.txt
===================================================================
--- lldb/source/Commands/CMakeLists.txt
+++ lldb/source/Commands/CMakeLists.txt
@@ -10,6 +10,7 @@
   CommandObjectCommands.cpp
   CommandObjectDiagnostics.cpp
   CommandObjectDisassemble.cpp
+  CommandObjectDWIMPrint.cpp
   CommandObjectExpression.cpp
   CommandObjectFrame.cpp
   CommandObjectGUI.cpp
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -1203,6 +1203,16 @@
   eTraceCursorSeekTypeEnd
 };
 
+/// Enum to control the verbosity level of `dwim-print` execution.
+enum DWIMPrintVerbosity {
+  /// Run `dwim-print` with no verbosity.
+  eDWIMPrintVerbosityNone,
+  /// Print a message when `dwim-print` uses `expression` evaluation.
+  eDWIMPrintVerbosityExpression,
+  /// Always print a message indicating how `dwim-print` is evaluating its
+  /// expression.
+  eDWIMPrintVerbosityFull,
+};
 
 } // namespace lldb
 
Index: lldb/include/lldb/Core/Debugger.h
===================================================================
--- lldb/include/lldb/Core/Debugger.h
+++ lldb/include/lldb/Core/Debugger.h
@@ -348,6 +348,8 @@
 
   bool SetTabSize(uint32_t tab_size);
 
+  lldb::DWIMPrintVerbosity GetDWIMPrintVerbosity() const;
+
   bool GetEscapeNonPrintables() const;
 
   bool GetNotifyVoid() const;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to