[Lldb-commits] [lldb] [lldb-dap] Allow setting scoped enums values (PR #192028)

Sergei Druzhkov via lldb-commits lldb-commits at lists.llvm.org
Tue Apr 14 02:18:35 PDT 2026


https://github.com/DrSergei created https://github.com/llvm/llvm-project/pull/192028

After this patch, users can set the value of a scoped enum in the VS Code UI using the fully qualified name of the enumerator instead of using integer representation before.

>From 49a6c6f9cd3b1b1d1e14bc164154deecc3984209 Mon Sep 17 00:00:00 2001
From: Sergei Druzhkov <serzhdruzhok at gmail.com>
Date: Tue, 14 Apr 2026 11:28:56 +0300
Subject: [PATCH] [lldb-dap] Allow setting scoped enums values

---
 .../lldb-dap/variables/TestDAP_variables.py   | 53 +++++++++++++------
 .../children/TestDAP_variables_children.py    |  1 -
 .../API/tools/lldb-dap/variables/main.cpp     |  8 +++
 .../Handler/SetVariableRequestHandler.cpp     |  9 +++-
 4 files changed, 54 insertions(+), 17 deletions(-)

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 66c8d7f720aef..4a5c428d41792 100644
--- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
+++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
@@ -351,9 +351,9 @@ def do_test_scopes_variables_setVariable_evaluate(
 
         verify_locals["argc"]["equals"]["value"] = "123"
         verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
-        verify_locals["x @ main.cpp:27"] = {"equals": {"type": "int", "value": "89"}}
-        verify_locals["x @ main.cpp:29"] = {"equals": {"type": "int", "value": "42"}}
-        verify_locals["x @ main.cpp:31"] = {"equals": {"type": "int", "value": "72"}}
+        verify_locals["x @ main.cpp:28"] = {"equals": {"type": "int", "value": "89"}}
+        verify_locals["x @ main.cpp:30"] = {"equals": {"type": "int", "value": "42"}}
+        verify_locals["x @ main.cpp:32"] = {"equals": {"type": "int", "value": "72"}}
 
         self.verify_variables(verify_locals, self.dap_server.get_local_variables())
 
@@ -361,22 +361,22 @@ def do_test_scopes_variables_setVariable_evaluate(
         self.assertFalse(self.set_local("x2", 9)["success"])
         self.assertFalse(self.set_local("x @ main.cpp:0", 9)["success"])
 
-        self.assertTrue(self.set_local("x @ main.cpp:27", 19)["success"])
-        self.assertTrue(self.set_local("x @ main.cpp:29", 21)["success"])
-        self.assertTrue(self.set_local("x @ main.cpp:31", 23)["success"])
+        self.assertTrue(self.set_local("x @ main.cpp:28", 19)["success"])
+        self.assertTrue(self.set_local("x @ main.cpp:30", 21)["success"])
+        self.assertTrue(self.set_local("x @ main.cpp:32", 23)["success"])
 
         # The following should have no effect
-        self.assertFalse(self.set_local("x @ main.cpp:31", "invalid")["success"])
+        self.assertFalse(self.set_local("x @ main.cpp:32", "invalid")["success"])
 
-        verify_locals["x @ main.cpp:27"]["equals"]["value"] = "19"
-        verify_locals["x @ main.cpp:29"]["equals"]["value"] = "21"
-        verify_locals["x @ main.cpp:31"]["equals"]["value"] = "23"
+        verify_locals["x @ main.cpp:28"]["equals"]["value"] = "19"
+        verify_locals["x @ main.cpp:30"]["equals"]["value"] = "21"
+        verify_locals["x @ main.cpp:32"]["equals"]["value"] = "23"
 
         self.verify_variables(verify_locals, self.dap_server.get_local_variables())
 
         # The plain x variable shold refer to the innermost x
         self.assertTrue(self.set_local("x", 22)["success"])
-        verify_locals["x @ main.cpp:31"]["equals"]["value"] = "22"
+        verify_locals["x @ main.cpp:32"]["equals"]["value"] = "22"
 
         self.verify_variables(verify_locals, self.dap_server.get_local_variables())
 
@@ -393,9 +393,9 @@ def do_test_scopes_variables_setVariable_evaluate(
         names = [var["name"] for var in locals]
         # The first shadowed x shouldn't have a suffix anymore
         verify_locals["x"] = {"equals": {"type": "int", "value": "19"}}
-        self.assertNotIn("x @ main.cpp:27", names)
-        self.assertNotIn("x @ main.cpp:29", names)
-        self.assertNotIn("x @ main.cpp:31", names)
+        self.assertNotIn("x @ main.cpp:28", names)
+        self.assertNotIn("x @ main.cpp:30", names)
+        self.assertNotIn("x @ main.cpp:32", names)
 
         self.verify_variables(verify_locals, locals)
 
@@ -428,12 +428,13 @@ def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: boo
             line_number(source, "// breakpoint 6"),
             line_number(source, "// breakpoint 7"),
             line_number(source, "// breakpoint 8"),
+            line_number(source, "// breakpoint 9"),
         ]
         breakpoint_ids = self.set_source_breakpoints(source, lines)
         self.assertEqual(
             len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
         )
-        [bp1, bp3, bp6, bp7, bp8] = breakpoint_ids
+        [bp1, bp3, bp6, bp7, bp8, bp9] = breakpoint_ids
         self.continue_to_breakpoint(bp1)
 
         # Verify locals
@@ -737,6 +738,28 @@ def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: boo
             inner_bitfields_struct,
         )
 
+        self.continue_to_breakpoint(bp9)
+
+        verify_locals = {
+            "t": {
+                "equals": {
+                    "type": "Test",
+                    "value": "FOO",
+                    "evaluateName": "t",
+                },
+            },
+        }
+        self.verify_variables(
+            verify_locals,
+            self.dap_server.get_local_variables(),
+        )
+        self.assertTrue(self.set_local("t", "Test::BAR")["success"])
+        verify_locals["t"]["equals"]["value"] = "BAR"
+        self.verify_variables(
+            verify_locals,
+            self.dap_server.get_local_variables(),
+        )
+
         # Continue to breakpoint 3, permanent variable should still exist
         # after resume.
         self.continue_to_breakpoint(bp3)
diff --git a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py
index 4622523931804..5f9e2383917f0 100644
--- a/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py
+++ b/lldb/test/API/tools/lldb-dap/variables/children/TestDAP_variables_children.py
@@ -24,7 +24,6 @@ def test_get_num_children(self):
         self.continue_to_breakpoints(breakpoint_ids)
 
         local_vars = self.dap_server.get_local_variables()
-        print(local_vars)
         indexed = next(filter(lambda x: x["name"] == "indexed", local_vars))
         not_indexed = next(filter(lambda x: x["name"] == "not_indexed", local_vars))
         self.assertIn("indexedVariables", indexed)
diff --git a/lldb/test/API/tools/lldb-dap/variables/main.cpp b/lldb/test/API/tools/lldb-dap/variables/main.cpp
index 6e17ebadc246f..e1a7fb165fc40 100644
--- a/lldb/test/API/tools/lldb-dap/variables/main.cpp
+++ b/lldb/test/API/tools/lldb-dap/variables/main.cpp
@@ -15,6 +15,7 @@ int test_return_variable();
 int test_anonymous_types();
 int test_anonymous_fields();
 void test_unnamed_bitfields();
+void test_scoped_enums();
 
 int main(int argc, char const *argv[]) {
   static float s_local = 2.25;
@@ -38,6 +39,7 @@ int main(int argc, char const *argv[]) {
   test_anonymous_types();
   test_anonymous_fields();
   test_unnamed_bitfields();
+  test_scoped_enums();
   return test_indexedVariables(); // breakpoint 3
 }
 
@@ -88,3 +90,9 @@ void test_unnamed_bitfields() {
   example e = {0xA, 0xB};
   printf("lo: %u, hi: %u\n", e.lo, e.hi); // breakpoint 8
 }
+
+void test_scoped_enums() {
+  enum class Test { FOO, BAR };
+  Test t = Test::FOO;
+  printf("enum: %i", static_cast<int>(t)); // breakpoint 9
+}
diff --git a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp
index 47a45ab807854..e27de395404fa 100644
--- a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp
@@ -64,7 +64,14 @@ SetVariableRequestHandler::Run(const SetVariableArguments &args) const {
   lldb::SBFrame frame = variable.GetFrame();
   std::string expression = llvm::StringRef(args.value).trim().str();
   lldb::SBValue result = EvaluateExpression(dap.target, frame, expression);
-  const char *value = result.IsValid() ? result.GetValue() : expression.c_str();
+  const char *value = [&]() {
+    if (!result.IsValid())
+      return expression.c_str();
+    lldb::SBType type = result.GetType();
+    if (type.IsScopedEnumerationType())
+      return result.Cast(type.GetEnumerationIntegerType()).GetValue();
+    return result.GetValue();
+  }();
 
   lldb::SBError error;
   const bool success = variable.SetValueFromCString(value, error);



More information about the lldb-commits mailing list