This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG34885bffdf43: [lldb-vscode] Handle request_evaluate's
context attribute (authored by Walter Erquinigo <[email protected]>).
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D98656/new/
https://reviews.llvm.org/D98656
Files:
lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
lldb/test/API/tools/lldb-vscode/evaluate/Makefile
lldb/test/API/tools/lldb-vscode/evaluate/TestVSCode_evaluate.py
lldb/test/API/tools/lldb-vscode/evaluate/foo.cpp
lldb/test/API/tools/lldb-vscode/evaluate/foo.h
lldb/test/API/tools/lldb-vscode/evaluate/main.cpp
lldb/tools/lldb-vscode/lldb-vscode.cpp
Index: lldb/tools/lldb-vscode/lldb-vscode.cpp
===================================================================
--- lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -1125,6 +1125,7 @@
auto arguments = request.getObject("arguments");
lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments);
const auto expression = GetString(arguments, "expression");
+ llvm::StringRef context = GetString(arguments, "context");
if (!expression.empty() && expression[0] == '`') {
auto result =
@@ -1133,13 +1134,17 @@
body.try_emplace("variablesReference", (int64_t)0);
} else {
// Always try to get the answer from the local variables if possible. If
- // this fails, then actually evaluate an expression using the expression
- // parser. "frame variable" is more reliable than the expression parser in
+ // this fails, then if the context is not "hover", actually evaluate an
+ // expression using the expression parser.
+ //
+ // "frame variable" is more reliable than the expression parser in
// many cases and it is faster.
lldb::SBValue value = frame.GetValueForVariablePath(
expression.data(), lldb::eDynamicDontRunTarget);
- if (value.GetError().Fail())
+
+ if (value.GetError().Fail() && context != "hover")
value = frame.EvaluateExpression(expression.data());
+
if (value.GetError().Fail()) {
response["success"] = llvm::json::Value(false);
// This error object must live until we're done with the pointer returned
Index: lldb/test/API/tools/lldb-vscode/evaluate/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-vscode/evaluate/main.cpp
@@ -0,0 +1,29 @@
+#include "foo.h"
+
+static int static_int = 42;
+
+int non_static_int = 43;
+
+int a_function(int var) {
+ return var; // breakpoint 3
+}
+
+struct my_struct {
+ int foo;
+};
+
+int main(int argc, char const *argv[]) {
+ my_struct struct1 = {15};
+ my_struct *struct2 = new my_struct{16};
+ int var1 = 20;
+ int var2 = 21;
+ int var3 = static_int; // breakpoint 1
+ {
+ int non_static_int = 10;
+ int var2 = 2;
+ int var3 = non_static_int; // breakpoint 2
+ }
+ a_function(var3);
+ foo_func();
+ return 0;
+}
Index: lldb/test/API/tools/lldb-vscode/evaluate/foo.h
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-vscode/evaluate/foo.h
@@ -0,0 +1,3 @@
+int foo_func();
+
+extern int foo_var;
Index: lldb/test/API/tools/lldb-vscode/evaluate/foo.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-vscode/evaluate/foo.cpp
@@ -0,0 +1,5 @@
+#include "foo.h"
+
+int foo_func() { return 43; }
+
+int foo_var = 44;
Index: lldb/test/API/tools/lldb-vscode/evaluate/TestVSCode_evaluate.py
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-vscode/evaluate/TestVSCode_evaluate.py
@@ -0,0 +1,157 @@
+"""
+Test lldb-vscode completions request
+"""
+
+
+import lldbvscode_testcase
+import unittest2
+import vscode
+from lldbsuite.test import lldbutil
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+class TestVSCode_variables(lldbvscode_testcase.VSCodeTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def assertEvaluate(self, expression, regex):
+ self.assertRegexpMatches(
+ self.vscode.request_evaluate(expression, context=self.context)['body']['result'],
+ regex)
+
+ def assertEvaluateFailure(self, expression):
+ self.assertNotIn('result',
+ self.vscode.request_evaluate(expression, context=self.context)['body'])
+
+ def isExpressionParsedExpected(self):
+ return self.context != "hover"
+
+ def run_test_evaluate_expressions(self, context=None):
+ """
+ Tests the evaluate expression request at different breakpoints
+ """
+ self.context = context
+ program = self.getBuildArtifact("a.out")
+ self.build_and_launch(program)
+ source = "main.cpp"
+ self.set_source_breakpoints(
+ source,
+ [
+ line_number(source, "// breakpoint 1"),
+ line_number(source, "// breakpoint 2"),
+ line_number(source, "// breakpoint 3")
+ ]
+ )
+ self.continue_to_next_stop()
+
+ # Expressions at breakpoint 1, which is in main
+ self.assertEvaluate("var1", "20")
+ self.assertEvaluate("var2", "21")
+ self.assertEvaluate("static_int", "42")
+ self.assertEvaluate("non_static_int", "43")
+ self.assertEvaluate("struct1", "my_struct @ 0x.*")
+ self.assertEvaluate("struct1.foo", "15")
+ self.assertEvaluate("struct2->foo", "16")
+
+ self.assertEvaluateFailure("var") # local variable of a_function
+ self.assertEvaluateFailure("my_struct") # type name
+ self.assertEvaluateFailure("int") # type name
+ self.assertEvaluateFailure("foo") # member of my_struct
+
+ if self.isExpressionParsedExpected():
+ self.assertEvaluate(
+ "a_function",
+ "0x.* \(a.out`a_function\(int\) at main.cpp:7\)")
+ self.assertEvaluate("a_function(1)", "1")
+ self.assertEvaluate("var2 + struct1.foo", "36")
+ self.assertEvaluate(
+ "foo_func",
+ "0x.* \(a.out`foo_func\(\) at foo.cpp:3\)")
+ self.assertEvaluate("foo_var", "44")
+ else:
+ self.assertEvaluateFailure("a_function")
+ self.assertEvaluateFailure("a_function(1)")
+ self.assertEvaluateFailure("var2 + struct1.foo")
+ self.assertEvaluateFailure("foo_func")
+ self.assertEvaluateFailure("foo_var")
+
+ # Expressions at breakpoint 2, which is an anonymous block
+ self.continue_to_next_stop()
+ self.assertEvaluate("var1", "20")
+ self.assertEvaluate("var2", "2") # different variable with the same name
+ self.assertEvaluate("static_int", "42")
+ self.assertEvaluate("non_static_int", "10") # different variable with the same name
+ self.assertEvaluate("struct1", "my_struct @ 0x.*")
+ self.assertEvaluate("struct1.foo", "15")
+ self.assertEvaluate("struct2->foo", "16")
+
+ if self.isExpressionParsedExpected():
+ self.assertEvaluate(
+ "a_function",
+ "0x.* \(a.out`a_function\(int\) at main.cpp:7\)")
+ self.assertEvaluate("a_function(1)", "1")
+ self.assertEvaluate("var2 + struct1.foo", "17")
+ self.assertEvaluate(
+ "foo_func",
+ "0x.* \(a.out`foo_func\(\) at foo.cpp:3\)")
+ self.assertEvaluate("foo_var", "44")
+ else:
+ self.assertEvaluateFailure("a_function")
+ self.assertEvaluateFailure("a_function(1)")
+ self.assertEvaluateFailure("var2 + struct1.foo")
+ self.assertEvaluateFailure("foo_func")
+ self.assertEvaluateFailure("foo_var")
+
+ # Expressions at breakpoint 3, which is inside a_function
+ self.continue_to_next_stop()
+ self.assertEvaluate("var", "42")
+ self.assertEvaluate("static_int", "42")
+ self.assertEvaluate("non_static_int", "43")
+
+ self.assertEvaluateFailure("var1")
+ self.assertEvaluateFailure("var2")
+ self.assertEvaluateFailure("struct1")
+ self.assertEvaluateFailure("struct1.foo")
+ self.assertEvaluateFailure("struct2->foo")
+ self.assertEvaluateFailure("var2 + struct1.foo")
+
+ if self.isExpressionParsedExpected():
+ self.assertEvaluate(
+ "a_function",
+ "0x.* \(a.out`a_function\(int\) at main.cpp:7\)")
+ self.assertEvaluate("a_function(1)", "1")
+ self.assertEvaluate("var + 1", "43")
+ self.assertEvaluate(
+ "foo_func",
+ "0x.* \(a.out`foo_func\(\) at foo.cpp:3\)")
+ self.assertEvaluate("foo_var", "44")
+ else:
+ self.assertEvaluateFailure("a_function")
+ self.assertEvaluateFailure("a_function(1)")
+ self.assertEvaluateFailure("var + 1")
+ self.assertEvaluateFailure("foo_func")
+ self.assertEvaluateFailure("foo_var")
+
+ @skipIfWindows
+ @skipIfRemote
+ def test_generic_evaluate_expressions(self):
+ # Tests context-less expression evaluations
+ self.run_test_evaluate_expressions()
+
+ @skipIfWindows
+ @skipIfRemote
+ def test_repl_evaluate_expressions(self):
+ # Tests expression evaluations that are triggered from the Debug Console
+ self.run_test_evaluate_expressions("repl")
+
+ @skipIfWindows
+ @skipIfRemote
+ def test_watch_evaluate_expressions(self):
+ # Tests expression evaluations that are triggered from a watch expression
+ self.run_test_evaluate_expressions("watch")
+
+ @skipIfWindows
+ @skipIfRemote
+ def test_hover_evaluate_expressions(self):
+ # Tests expression evaluations that are triggered when hovering on the editor
+ self.run_test_evaluate_expressions("hover")
Index: lldb/test/API/tools/lldb-vscode/evaluate/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/tools/lldb-vscode/evaluate/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp foo.cpp
+
+include Makefile.rules
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
@@ -139,7 +139,7 @@
for module in module_list:
modules[module['name']] = module
return modules
-
+
def get_output(self, category, timeout=0.0, clear=True):
self.output_condition.acquire()
output = None
@@ -304,7 +304,7 @@
return response_or_request
else:
if response_or_request['command'] == 'runInTerminal':
- subprocess.Popen(response_or_request['arguments']['args'],
+ subprocess.Popen(response_or_request['arguments']['args'],
env=response_or_request['arguments']['env'])
self.send_packet({
"type": "response",
@@ -317,7 +317,7 @@
else:
desc = 'unkonwn reverse request "%s"' % (response_or_request['command'])
raise ValueError(desc)
-
+
return None
def wait_for_event(self, filter=None, timeout=None):
@@ -567,13 +567,14 @@
}
return self.send_recv(command_dict)
- def request_evaluate(self, expression, frameIndex=0, threadId=None):
+ def request_evaluate(self, expression, frameIndex=0, threadId=None, context=None):
stackFrame = self.get_stackFrame(frameIndex=frameIndex,
threadId=threadId)
if stackFrame is None:
return []
args_dict = {
'expression': expression,
+ 'context': context,
'frameId': stackFrame['id'],
}
command_dict = {
@@ -787,7 +788,7 @@
}
response = self.send_recv(command_dict)
return response
-
+
def request_completions(self, text):
args_dict = {
'text': text,
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits