[Lldb-commits] [lldb] 995eb4c - [lldb-dap] Add readOnly attribute for variables (#151884)

via lldb-commits lldb-commits at lists.llvm.org
Wed Oct 15 13:46:12 PDT 2025


Author: Sergei Druzhkov
Date: 2025-10-15T23:46:07+03:00
New Revision: 995eb4ca2ee15daffcc5a20121de955a0e2ca023

URL: https://github.com/llvm/llvm-project/commit/995eb4ca2ee15daffcc5a20121de955a0e2ca023
DIFF: https://github.com/llvm/llvm-project/commit/995eb4ca2ee15daffcc5a20121de955a0e2ca023.diff

LOG: [lldb-dap] Add readOnly attribute for variables (#151884)

This patch adds `readOnly`
[attribute](https://microsoft.github.io/debug-adapter-protocol/specification#Types_VariablePresentationHint)
for variables. When this attribute is returned for a variable, VS Code
prevents editing (and grays out the `Set Value` button). Without this,
users might be confused if the UI allows edits but the debug adapter
often returns an error. I checked `SetValueFromCString` function
implementation and found that it doesn't support aggregate data types,
so I added simple check for them. Also, I found that I can update value
of registers sets (but without any effects). So I also added checks for
those as well.

Added: 
    

Modified: 
    lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
    lldb/tools/lldb-dap/ProtocolUtils.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
index 13a694602f230..977d6ce9dac8a 100644
--- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
+++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
@@ -65,6 +65,11 @@ def verify_values(self, verify_dict, actual, varref_dict=None, expression=None):
                 self.assertNotIn(
                     key, actual, 'key "%s" is not expected in %s' % (key, actual)
                 )
+        isReadOnly = verify_dict.get("readOnly", False)
+        attributes = actual.get("presentationHint", {}).get("attributes", [])
+        self.assertEqual(
+            isReadOnly, "readOnly" in attributes, "%s %s" % (verify_dict, actual)
+        )
         hasVariablesReference = "variablesReference" in actual
         varRef = None
         if hasVariablesReference:
@@ -179,8 +184,9 @@ def do_test_scopes_variables_setVariable_evaluate(
                 "children": {
                     "x": {"equals": {"type": "int", "value": "11"}},
                     "y": {"equals": {"type": "int", "value": "22"}},
-                    "buffer": {"children": buffer_children},
+                    "buffer": {"children": buffer_children, "readOnly": True},
                 },
+                "readOnly": True,
             },
             "x": {"equals": {"type": "int"}},
         }
@@ -444,8 +450,10 @@ def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: boo
                     "buffer": {
                         "children": buffer_children,
                         "equals": {"indexedVariables": 16},
+                        "readOnly": True,
                     },
                 },
+                "readOnly": True,
             },
             "x": {
                 "equals": {"type": "int"},
@@ -528,7 +536,7 @@ def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: boo
             "children": {
                 "x": {"equals": {"type": "int", "value": "11"}},
                 "y": {"equals": {"type": "int", "value": "22"}},
-                "buffer": {"children": buffer_children},
+                "buffer": {"children": buffer_children, "readOnly": True},
             },
         }
 
@@ -622,11 +630,17 @@ def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
         # "[raw]" child.
         raw_child_count = 1 if enableSyntheticChildDebugging else 0
         verify_locals = {
-            "small_array": {"equals": {"indexedVariables": 5}},
-            "large_array": {"equals": {"indexedVariables": 200}},
-            "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}},
-            "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}},
-            "pt": {"missing": ["indexedVariables"]},
+            "small_array": {"equals": {"indexedVariables": 5}, "readOnly": True},
+            "large_array": {"equals": {"indexedVariables": 200}, "readOnly": True},
+            "small_vector": {
+                "equals": {"indexedVariables": 5 + raw_child_count},
+                "readOnly": True,
+            },
+            "large_vector": {
+                "equals": {"indexedVariables": 200 + raw_child_count},
+                "readOnly": True,
+            },
+            "pt": {"missing": ["indexedVariables"], "readOnly": True},
         }
         self.verify_variables(verify_locals, locals)
 
@@ -640,7 +654,10 @@ def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
             "[4]": {"equals": {"type": "int", "value": "0"}},
         }
         if enableSyntheticChildDebugging:
-            verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},)
+            verify_children["[raw]"] = {
+                "contains": {"type": ["vector"]},
+                "readOnly": True,
+            }
 
         children = self.dap_server.request_variables(locals[2]["variablesReference"])[
             "body"
@@ -660,7 +677,7 @@ def test_return_variables(self):
             return_name: {"equals": {"type": "int", "value": "300"}},
             "argc": {},
             "argv": {},
-            "pt": {},
+            "pt": {"readOnly": True},
             "x": {},
             "return_result": {"equals": {"type": "int"}},
         }

diff  --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp b/lldb/tools/lldb-dap/ProtocolUtils.cpp
index 775c82fbb7716..868c67ca72986 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -301,6 +301,14 @@ Variable CreateVariable(lldb::SBValue v, int64_t var_ref, bool format_hex,
   if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
     var.memoryReference = addr;
 
+  bool is_readonly = v.GetType().IsAggregateType() ||
+                     v.GetValueType() == lldb::eValueTypeRegisterSet;
+  if (is_readonly) {
+    if (!var.presentationHint)
+      var.presentationHint = {VariablePresentationHint()};
+    var.presentationHint->attributes.push_back("readOnly");
+  }
+
   return var;
 }
 


        


More information about the lldb-commits mailing list