https://github.com/Nerixyz updated 
https://github.com/llvm/llvm-project/pull/204431

>From fb9e6efa387e56ba69d15bdf46e5764621913a9d Mon Sep 17 00:00:00 2001
From: Nerixyz <[email protected]>
Date: Wed, 17 Jun 2026 21:44:16 +0200
Subject: [PATCH 1/3] [lldb] Treat synthetic variables as locals

---
 .../Process/scripted/ScriptedFrame.cpp        |  5 ++--
 .../TestScriptedFrameProvider.py              | 25 ++++++++++++++++---
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp 
b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
index 72a7169d01188..2bb47dd29c2df 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
@@ -307,10 +307,11 @@ void ScriptedFrame::PopulateVariableListFromInterface(
 
     VariableSP var = v->GetVariable();
     if (!var && include_synthetic_vars) {
-      // Construct the value type as an synthetic verison of what the value 
type
+      // Construct the value type as an synthetic version of what the value 
type
       // is. That'll allow the user to tell the scope and the 'synthetic-ness'
       // of the variable.
-      lldb::ValueType vt = GetSyntheticValueType(v->GetValueType());
+      // Any variable we create here will be treated as a local variable.
+      lldb::ValueType vt = GetSyntheticValueType(eValueTypeVariableLocal);
 
       // Just make up a variable - the frame variable dumper just passes it
       // back in to GetValueObjectForFrameVariable, so we really just need to
diff --git 
a/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py
 
b/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py
index 597447723047e..b715d99964569 100644
--- 
a/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py
+++ 
b/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py
@@ -824,26 +824,43 @@ def test_get_values(self):
         options = lldb.SBVariablesOptions()
         options.SetIncludeSynthetic(True)
         variables = frame0.GetVariables(options)
+        self.assertFalse(variables.IsValid())
+        self.assertEqual(variables.GetSize(), 0)
+
+        options.SetIncludeLocals(True)
+        variables = frame0.GetVariables(options)
         self.assertTrue(variables.IsValid())
-        self.assertTrue(variables.GetValueAtIndex(0).name == "_handler_one")
+        self.assertEqual(variables.GetSize(), 2)
+        self.assertEqual(variables.GetValueAtIndex(0).name, "variable_in_main")
+        self.assertEqual(variables.GetValueAtIndex(1).name, "_handler_one")
 
         # Ensure that we get synthetic variables in the other overloads.
         # (arguments, locals, statics, in_scope_only)
         variables = frame0.GetVariables(False, False, False, False)
+        self.assertFalse(variables.IsValid())
+        self.assertEqual(variables.GetSize(), 0)
+        variables = frame0.GetVariables(False, True, False, False)
         self.assertTrue(variables.IsValid())
-        self.assertTrue(variables.GetValueAtIndex(0).name == "_handler_one")
+        self.assertEqual(variables.GetSize(), 2)
+        self.assertEqual(variables.GetValueAtIndex(0).name, "variable_in_main")
+        self.assertEqual(variables.GetValueAtIndex(1).name, "_handler_one")
 
         # (arguments, locals, statics, in_scope_only, use_dynamic)
         variables = frame0.GetVariables(
-            False, False, False, False, lldb.eNoDynamicValues
+            False, True, False, False, lldb.eNoDynamicValues
         )
         self.assertTrue(variables.IsValid())
-        self.assertTrue(variables.GetValueAtIndex(0).name == "_handler_one")
+        self.assertEqual(variables.GetSize(), 2)
+        self.assertEqual(variables.GetValueAtIndex(0).name, "variable_in_main")
+        self.assertEqual(variables.GetValueAtIndex(1).name, "_handler_one")
 
         # FIXME: Synthetic variables are never in scope.
         variables = frame0.GetVariables(False, False, False, True)
         self.assertFalse(variables.IsValid())
         self.assertEqual(variables.GetSize(), 0)
+        variables = frame0.GetVariables(False, True, False, True)
+        self.assertFalse(variables.IsValid())
+        self.assertEqual(variables.GetSize(), 0)
 
         # Check the `frame variable` command(s) handle synthetic variables the
         # way we expect by printing them.

>From 49965ff92280208c435f224732df48f7d18754fd Mon Sep 17 00:00:00 2001
From: Nerixyz <[email protected]>
Date: Wed, 24 Jun 2026 17:52:51 +0200
Subject: [PATCH 2/3] refactor: Ask the frame what value type it wants

---
 .../Interfaces/ScriptedFrameInterface.h       |  5 ++
 .../Process/scripted/ScriptedFrame.cpp        | 50 ++++++++++---------
 .../ScriptedFramePythonInterface.cpp          | 16 ++++++
 .../Interfaces/ScriptedFramePythonInterface.h |  3 ++
 .../Interfaces/ScriptedPythonInterface.cpp    | 21 ++++++++
 .../Interfaces/ScriptedPythonInterface.h      |  5 ++
 .../test_frame_providers.py                   |  5 ++
 7 files changed, 82 insertions(+), 23 deletions(-)

diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h 
b/lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h
index 00994d65fd601..43914ef705dbf 100644
--- a/lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h
@@ -53,6 +53,11 @@ class ScriptedFrameInterface : virtual public 
ScriptedInterface {
 
   virtual lldb::ValueObjectListSP GetVariables() { return nullptr; }
 
+  virtual std::optional<lldb::ValueType>
+  GetValueTypeForVariable(lldb::ValueObjectSP value) {
+    return std::nullopt;
+  }
+
   virtual lldb::ValueObjectSP
   GetValueObjectForVariableExpression(llvm::StringRef expr, uint32_t options,
                                       Status &error) {
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp 
b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
index 2bb47dd29c2df..8adc69b1f6cc6 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
@@ -300,35 +300,39 @@ void ScriptedFrame::PopulateVariableListFromInterface(
 
   // Convert what we can into a variable.
   m_variable_list_sp = std::make_shared<VariableList>();
+
   for (uint32_t i = 0, e = value_list_sp->GetSize(); i < e; ++i) {
     ValueObjectSP v = value_list_sp->GetValueObjectAtIndex(i);
     if (!v)
       continue;
 
-    VariableSP var = v->GetVariable();
-    if (!var && include_synthetic_vars) {
-      // Construct the value type as an synthetic version of what the value 
type
-      // is. That'll allow the user to tell the scope and the 'synthetic-ness'
-      // of the variable.
-      // Any variable we create here will be treated as a local variable.
-      lldb::ValueType vt = GetSyntheticValueType(eValueTypeVariableLocal);
-
-      // Just make up a variable - the frame variable dumper just passes it
-      // back in to GetValueObjectForFrameVariable, so we really just need to
-      // make sure the name and type are correct. We create IDs based on
-      // value_list_sp in order to make sure they're unique.
-      var = std::make_shared<lldb_private::Variable>(
-          (lldb::user_id_t)value_list_sp->GetSize() + i,
-          v->GetName().GetCString(), v->GetName().GetCString(), nullptr, vt,
-          /*owner_scope=*/nullptr,
-          /*scope_range=*/Variable::RangeList{},
-          /*decl=*/nullptr, DWARFExpressionList{}, /*external=*/false,
-          /*artificial=*/true, /*location_is_constant_data=*/false);
-    }
+    // Ask the interface about the value type of this variable. If it doesn't
+    // specify any, use the original value type. If we encounter a variable, 
use
+    // a non-synthetic type unless it's overwritten.
+    std::optional<lldb::ValueType> desired_vt =
+        GetInterface()->GetValueTypeForVariable(v);
+    lldb::ValueType vt = [&] {
+      if (desired_vt)
+        return GetSyntheticValueType(*desired_vt);
+      if (v->GetVariable())
+        return v->GetValueType();
+      return GetSyntheticValueType(v->GetValueType());
+    }();
+
+    if (IsSyntheticValueType(vt) && !include_synthetic_vars)
+      continue;
 
-    // Only append the variable if we have one (had already, or just created).
-    if (var)
-      m_variable_list_sp->AddVariable(var);
+    // Just make up a variable - the frame variable dumper just passes it
+    // back in to GetValueObjectForFrameVariable, so we really just need to
+    // make sure the name and type are correct. We create IDs based on
+    // value_list_sp in order to make sure they're unique.
+    m_variable_list_sp->AddVariable(std::make_shared<lldb_private::Variable>(
+        (lldb::user_id_t)value_list_sp->GetSize() + i,
+        v->GetName().GetCString(), v->GetName().GetCString(), nullptr, vt,
+        /*owner_scope=*/nullptr,
+        /*scope_range=*/Variable::RangeList{},
+        /*decl=*/nullptr, DWARFExpressionList{}, /*external=*/false,
+        /*artificial=*/true, /*location_is_constant_data=*/false));
   }
 }
 
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
index de987c3773d88..6cc5ebff2c10b 100644
--- 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
@@ -11,6 +11,7 @@
 #include "lldb/Host/Config.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/ValueObject/ValueObject.h"
 #include "lldb/lldb-enumerations.h"
 
 #include "../SWIGPythonBridge.h"
@@ -163,6 +164,21 @@ lldb::ValueObjectListSP 
ScriptedFramePythonInterface::GetVariables() {
   return vals;
 }
 
+std::optional<lldb::ValueType>
+ScriptedFramePythonInterface::GetValueTypeForVariable(
+    lldb::ValueObjectSP value) {
+  Status error;
+  auto val = Dispatch<std::optional<lldb::ValueType>>(
+      "get_value_type_for_variable", error, std::move(value));
+
+  if (error.Fail()) {
+    return ErrorWithMessage<std::optional<lldb::ValueType>>(
+        LLVM_PRETTY_FUNCTION, error.AsCString(), error);
+  }
+
+  return val;
+}
+
 lldb::ValueObjectSP
 ScriptedFramePythonInterface::GetValueObjectForVariableExpression(
     llvm::StringRef expr, uint32_t options, Status &status) {
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
index 2e215bbe6aea2..9320c6762b35f 100644
--- 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
@@ -51,6 +51,9 @@ class ScriptedFramePythonInterface : public 
ScriptedFrameInterface,
 
   lldb::ValueObjectListSP GetVariables() override;
 
+  std::optional<lldb::ValueType>
+  GetValueTypeForVariable(lldb::ValueObjectSP value) override;
+
   lldb::ValueObjectSP
   GetValueObjectForVariableExpression(llvm::StringRef expr, uint32_t options,
                                       Status &status) override;
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index 84dbbbe7270d8..25d0c0dac5be0 100644
--- 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -322,3 +322,24 @@ 
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ValueObjectListSP>(
 
   return out;
 }
+
+template <>
+std::optional<lldb::ValueType>
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    std::optional<lldb::ValueType>>(python::PythonObject &p, Status &error) {
+  if (p.IsNone())
+    return std::nullopt;
+
+  llvm::Expected<unsigned long long> val = p.AsUnsignedLongLong();
+  if (!val) {
+    error = Status::FromError(val.takeError());
+    return std::nullopt;
+  }
+  if (*val > std::numeric_limits<std::underlying_type_t<ValueType>>::max()) {
+    error =
+        Status::FromErrorStringWithFormatv("value too large (got {0})", *val);
+    return std::nullopt;
+  }
+
+  return static_cast<ValueType>(*val);
+}
diff --git 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index 28ed5745ca55f..7d0d4cdd3c6d1 100644
--- 
a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ 
b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -836,6 +836,11 @@ lldb::ValueObjectListSP
 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ValueObjectListSP>(
     python::PythonObject &p, Status &error);
 
+template <>
+std::optional<lldb::ValueType>
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    std::optional<lldb::ValueType>>(python::PythonObject &p, Status &error);
+
 } // namespace lldb_private
 
 #endif // 
LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
diff --git 
a/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py 
b/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py
index f9f673f80abcf..91b3830fd195f 100644
--- 
a/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py
+++ 
b/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py
@@ -554,6 +554,11 @@ def is_hidden(self):
     def get_register_context(self):
         """No register context."""
         return None
+    
+    def get_value_type_for_variable(self, var):
+        if var.GetName() == "_handler_one":
+            return lldb.eValueTypeVariableLocal
+        return None # Inherit the value type for others.
 
     def get_variables(self):
         """"""

>From e76abb5fa54d6fb33cbd9c7001c046b5c88fe7c5 Mon Sep 17 00:00:00 2001
From: Nerixyz <[email protected]>
Date: Wed, 24 Jun 2026 17:57:39 +0200
Subject: [PATCH 3/3] fix: formatting

---
 .../scripted_frame_provider/test_frame_providers.py           | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git 
a/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py 
b/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py
index 91b3830fd195f..13a7d152f87ed 100644
--- 
a/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py
+++ 
b/lldb/test/API/functionalities/scripted_frame_provider/test_frame_providers.py
@@ -554,11 +554,11 @@ def is_hidden(self):
     def get_register_context(self):
         """No register context."""
         return None
-    
+
     def get_value_type_for_variable(self, var):
         if var.GetName() == "_handler_one":
             return lldb.eValueTypeVariableLocal
-        return None # Inherit the value type for others.
+        return None  # Inherit the value type for others.
 
     def get_variables(self):
         """"""

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to