[Lldb-commits] [lldb] 2011cbc - [lldb-dap] Add feature to remember last non-empty expression. (#107485)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 20 14:04:48 PDT 2024
Author: cmtice
Date: 2024-09-20T14:04:44-07:00
New Revision: 2011cbcd84102236dd6d58e2079ac676a3403f25
URL: https://github.com/llvm/llvm-project/commit/2011cbcd84102236dd6d58e2079ac676a3403f25
DIFF: https://github.com/llvm/llvm-project/commit/2011cbcd84102236dd6d58e2079ac676a3403f25.diff
LOG: [lldb-dap] Add feature to remember last non-empty expression. (#107485)
Update lldb-dap so if the user just presses return, which sends an empty
expression, it re-evaluates the most recent non-empty
expression/command. Also udpated test to test this case.
Added:
Modified:
lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
lldb/test/API/tools/lldb-dap/evaluate/main.cpp
lldb/tools/lldb-dap/DAP.h
lldb/tools/lldb-dap/LLDBUtils.cpp
lldb/tools/lldb-dap/lldb-dap.cpp
Removed:
################################################################################
diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
index 29548a835c6919..0126d40d86fca2 100644
--- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
+++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
@@ -54,13 +54,22 @@ def run_test_evaluate_expressions(
line_number(source, "// breakpoint 5"),
line_number(source, "// breakpoint 6"),
line_number(source, "// breakpoint 7"),
+ line_number(source, "// breakpoint 8"),
],
)
self.continue_to_next_stop()
# Expressions at breakpoint 1, which is in main
self.assertEvaluate("var1", "20")
+ # Empty expression should equate to the previous expression.
+ if context == "repl":
+ self.assertEvaluate("", "20")
+ else:
+ self.assertEvaluateFailure("")
self.assertEvaluate("var2", "21")
+ if context == "repl":
+ self.assertEvaluate("", "21")
+ self.assertEvaluate("", "21")
self.assertEvaluate("static_int", "42")
self.assertEvaluate("non_static_int", "43")
self.assertEvaluate("struct1.foo", "15")
@@ -191,6 +200,15 @@ def run_test_evaluate_expressions(
self.continue_to_next_stop()
self.assertEvaluate("my_bool_vec", "size=2")
+ # Test memory read, especially with 'empty' repeat commands.
+ if context == "repl":
+ self.continue_to_next_stop()
+ self.assertEvaluate("memory read -c 1 &my_ints", ".* 05 .*\n")
+ self.assertEvaluate("", ".* 0a .*\n")
+ self.assertEvaluate("", ".* 0f .*\n")
+ self.assertEvaluate("", ".* 14 .*\n")
+ self.assertEvaluate("", ".* 19 .*\n")
+
@skipIfWindows
def test_generic_evaluate_expressions(self):
# Tests context-less expression evaluations
diff --git a/lldb/test/API/tools/lldb-dap/evaluate/main.cpp b/lldb/test/API/tools/lldb-dap/evaluate/main.cpp
index ca27b5ba5ca19d..1c68716e3a6e11 100644
--- a/lldb/test/API/tools/lldb-dap/evaluate/main.cpp
+++ b/lldb/test/API/tools/lldb-dap/evaluate/main.cpp
@@ -1,5 +1,6 @@
#include "foo.h"
+#include <cstdint>
#include <map>
#include <vector>
@@ -45,5 +46,6 @@ int main(int argc, char const *argv[]) {
my_bool_vec.push_back(false); // breakpoint 6
my_bool_vec.push_back(true); // breakpoint 7
- return 0;
+ uint8_t my_ints[] = {5, 10, 15, 20, 25, 30};
+ return 0; // breakpoint 8
}
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index e28fd593ed74ce..bc2c055e2c56d5 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -205,6 +205,12 @@ struct DAP {
std::string command_escape_prefix = "`";
lldb::SBFormat frame_format;
lldb::SBFormat thread_format;
+ // This is used to allow request_evaluate to handle empty expressions
+ // (ie the user pressed 'return' and expects the previous expression to
+ // repeat). If the previous expression was a command, this string will be
+ // empty; if the previous expression was a variable expression, this string
+ // will contain that expression.
+ std::string last_nonempty_var_expression;
DAP();
~DAP();
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index ff6bea1b23eee8..a74b32609a167b 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -45,7 +45,8 @@ bool RunLLDBCommands(llvm::StringRef prefix,
// RunTerminateCommands.
static std::mutex handle_command_mutex;
std::lock_guard<std::mutex> locker(handle_command_mutex);
- interp.HandleCommand(command.str().c_str(), result);
+ interp.HandleCommand(command.str().c_str(), result,
+ /*add_to_history=*/true);
}
const bool got_error = !result.Succeeded();
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 2fb86f675b4516..93676d7add239d 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -1568,9 +1568,16 @@ void request_evaluate(const llvm::json::Object &request) {
lldb::SBFrame frame = g_dap.GetLLDBFrame(*arguments);
std::string expression = GetString(arguments, "expression").str();
llvm::StringRef context = GetString(arguments, "context");
-
- if (context == "repl" && g_dap.DetectExpressionContext(frame, expression) ==
- ExpressionContext::Command) {
+ bool repeat_last_command =
+ expression.empty() && g_dap.last_nonempty_var_expression.empty();
+
+ if (context == "repl" && (repeat_last_command ||
+ (!expression.empty() &&
+ g_dap.DetectExpressionContext(frame, expression) ==
+ ExpressionContext::Command))) {
+ // Since the current expression is not for a variable, clear the
+ // last_nonempty_var_expression field.
+ g_dap.last_nonempty_var_expression.clear();
// If we're evaluating a command relative to the current frame, set the
// focus_tid to the current frame for any thread related events.
if (frame.IsValid()) {
@@ -1581,6 +1588,16 @@ void request_evaluate(const llvm::json::Object &request) {
EmplaceSafeString(body, "result", result);
body.try_emplace("variablesReference", (int64_t)0);
} else {
+ if (context == "repl") {
+ // If the expression is empty and the last expression was for a
+ // variable, set the expression to the previous expression (repeat the
+ // evaluation); otherwise save the current non-empty expression for the
+ // next (possibly empty) variable expression.
+ if (expression.empty())
+ expression = g_dap.last_nonempty_var_expression;
+ else
+ g_dap.last_nonempty_var_expression = expression;
+ }
// Always try to get the answer from the local variables if possible. If
// this fails, then if the context is not "hover", actually evaluate an
// expression using the expression parser.
More information about the lldb-commits
mailing list