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 <wall...@fb.com>).
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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to