[Lldb-commits] [lldb] [lldb][SBAPI] Add new SBType::GetTemplateParameterValue API (PR #126901)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Wed Feb 12 05:45:59 PST 2025


https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/126901

>From d69bd14f285f5508abc35b60172efc8839b7c0fd Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 12 Feb 2025 12:27:22 +0000
Subject: [PATCH 1/5] [lldb][SBAPI] Add new SBType::GetTemplateParameterValue
 API

This patch adds a new API to `SBType` to retrieve the value of a
template parameter given an index. We re-use the
`TypeSystemClang::GetIntegralTemplateArgument` for this and thus currently only supports integral non-type template parameters. Types like float/double are not supported yet.

rdar://144395216
---
 lldb/include/lldb/API/SBTarget.h              |  1 +
 lldb/include/lldb/API/SBType.h                |  7 ++++
 lldb/include/lldb/API/SBValue.h               |  1 +
 lldb/source/API/SBType.cpp                    | 34 +++++++++++++++++++
 .../TestTemplatePackArgs.py                   | 19 +++++++++--
 .../API/lang/cpp/template-arguments/Makefile  |  1 +
 .../TestCppTemplateArguments.py               | 32 +++++++++++++++--
 .../API/lang/cpp/template-arguments/main.cpp  |  5 +++
 8 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 9b97359d49cf9..bb912ab41d0fe 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -964,6 +964,7 @@ class LLDB_API SBTarget {
   friend class SBSection;
   friend class SBSourceManager;
   friend class SBSymbol;
+  friend class SBType;
   friend class SBTypeStaticField;
   friend class SBValue;
   friend class SBVariablesOptions;
diff --git a/lldb/include/lldb/API/SBType.h b/lldb/include/lldb/API/SBType.h
index 63ba91082d576..9ad3244686328 100644
--- a/lldb/include/lldb/API/SBType.h
+++ b/lldb/include/lldb/API/SBType.h
@@ -221,6 +221,13 @@ class SBType {
 
   lldb::SBType GetTemplateArgumentType(uint32_t idx);
 
+  /// Returns the value of the non-type template parameter at index \c idx.
+  /// If \c idx is out-of-bounds or the template parameter doesn't have
+  /// a value, returns an empty SBValue.
+  ///
+  /// This function will expand parameter packs.
+  lldb::SBValue GetTemplateArgumentValue(lldb::SBTarget target, uint32_t idx);
+
   /// Return the TemplateArgumentKind of the template argument at index idx.
   /// Variadic argument packs are automatically expanded.
   lldb::TemplateArgumentKind GetTemplateArgumentKind(uint32_t idx);
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
index 9090cece80f7c..46ef6daa95264 100644
--- a/lldb/include/lldb/API/SBValue.h
+++ b/lldb/include/lldb/API/SBValue.h
@@ -446,6 +446,7 @@ class LLDB_API SBValue {
   friend class SBModule;
   friend class SBTarget;
   friend class SBThread;
+  friend class SBType;
   friend class SBTypeStaticField;
   friend class SBTypeSummary;
   friend class SBValueList;
diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index 4cc16c64e4756..8d04e9650b781 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -687,6 +687,40 @@ lldb::TemplateArgumentKind SBType::GetTemplateArgumentKind(uint32_t idx) {
   return eTemplateArgumentKindNull;
 }
 
+lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target,
+                                               uint32_t idx) {
+  LLDB_INSTRUMENT_VA(this, target, idx);
+
+  if (!IsValid())
+    return SBValue();
+
+  std::optional<CompilerType::IntegralTemplateArgument> arg;
+  const bool expand_pack = true;
+  switch (GetTemplateArgumentKind(idx)) {
+  case eTemplateArgumentKindIntegral:
+    arg = m_opaque_sp->GetCompilerType(false).GetIntegralTemplateArgument(
+        idx, expand_pack);
+    break;
+  default:
+    break;
+  }
+
+  if (!arg)
+    return {};
+
+  Scalar value{arg->value};
+
+  if (!value.IsValid())
+    return {};
+
+  DataExtractor data;
+  value.GetData(data);
+
+  auto value_obj_sp = ValueObjectConstResult::Create(
+      target.GetSP().get(), arg->type, ConstString("value"), data);
+  return SBValue(std::move(value_obj_sp));
+}
+
 SBType SBType::FindDirectNestedType(const char *name) {
   LLDB_INSTRUMENT_VA(this, name);
 
diff --git a/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py b/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
index c571357ff6720..f2467cbea9439 100644
--- a/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
+++ b/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
@@ -11,7 +11,7 @@
 class TemplatePackArgsTestCase(TestBase):
     def test_template_argument_pack(self):
         self.build()
-        (_, _, thread, _) = lldbutil.run_to_source_breakpoint(
+        (target, _, thread, _) = lldbutil.run_to_source_breakpoint(
             self, "breakpoint here", lldb.SBFileSpec("main.cpp"), exe_name="a.out"
         )
         frame = thread.GetSelectedFrame()
@@ -33,10 +33,25 @@ def test_template_argument_pack(self):
         self.assertEqual(
             only_pack.GetType().GetTemplateArgumentType(2).GetName(), "double"
         )
-        # Access the C<double, 42> template parameter.
+
         nested_template = only_pack.GetType().GetTemplateArgumentType(3)
         self.assertEqual(nested_template.GetName(), "D<int, int, bool>")
         self.assertEqual(nested_template.GetNumberOfTemplateArguments(), 3)
         self.assertEqual(nested_template.GetTemplateArgumentType(0).GetName(), "int")
         self.assertEqual(nested_template.GetTemplateArgumentType(1).GetName(), "int")
         self.assertEqual(nested_template.GetTemplateArgumentType(2).GetName(), "bool")
+
+        my_c = frame.FindVariable("myC")
+        self.assertTrue(my_c.IsValid(), "make sure we find the myC variable")
+
+        # Out of bounds index.
+        self.assertFalse(my_c.GetType().GetTemplateArgumentValue(target, 3))
+
+        # Out of bounds index.
+        template_param_value = my_c.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertEqual(template_param_value.GetTypeName(), "int")
+        self.assertEqual(template_param_value.GetValueAsSigned(), 16)
+
+        template_param_value = my_c.GetType().GetTemplateArgumentValue(target, 2)
+        self.assertEqual(template_param_value.GetTypeName(), "int")
+        self.assertEqual(template_param_value.GetValueAsSigned(), 32)
diff --git a/lldb/test/API/lang/cpp/template-arguments/Makefile b/lldb/test/API/lang/cpp/template-arguments/Makefile
index 99998b20bcb05..4f79c0a900c3a 100644
--- a/lldb/test/API/lang/cpp/template-arguments/Makefile
+++ b/lldb/test/API/lang/cpp/template-arguments/Makefile
@@ -1,3 +1,4 @@
 CXX_SOURCES := main.cpp
+CXXFLAGS_EXTRAS := -std=c++20
 
 include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
index 7b63a6cca8db4..eb5959c2a3668 100644
--- a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
+++ b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
@@ -8,7 +8,7 @@ class TestCase(TestBase):
     @no_debug_info_test
     def test(self):
         self.build()
-        self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
 
         value = self.expect_expr("temp1", result_type="C<int, 2>")
         template_type = value.GetType()
@@ -27,10 +27,38 @@ def test(self):
         self.assertEqual(
             template_type.GetTemplateArgumentType(1).GetName(), "unsigned int"
         )
-        # FIXME: There is no way to get the actual value of the parameter.
+
+        # Template parameter isn't a NTTP.
+        self.assertFalse(template_type.GetTemplateArgumentValue(target, 0))
+
+        # Template parameter index out-of-bounds.
+        self.assertFalse(template_type.GetTemplateArgumentValue(target, 2))
+
+        # Template parameter is a NTTP.
+        param_val = template_type.GetTemplateArgumentValue(target, 1)
+        self.assertEqual(param_val.GetTypeName(), "unsigned int")
+        self.assertEqual(param_val.GetValueAsUnsigned(), 2)
 
         # Try to get an invalid template argument.
         self.assertEqual(
             template_type.GetTemplateArgumentKind(2), lldb.eTemplateArgumentKindNull
         )
         self.assertEqual(template_type.GetTemplateArgumentType(2).GetName(), "")
+
+        value = self.expect_expr("temp2", result_type="Foo<short, -2>")
+        template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertTrue(template_param_value)
+        self.assertEqual(template_param_value.GetTypeName(), "short")
+        self.assertEqual(template_param_value.GetValueAsSigned(), -2)
+
+        value = self.expect_expr("temp3", result_type="Foo<char, 'v'>")
+        template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertTrue(template_param_value)
+        self.assertEqual(template_param_value.GetTypeName(), "char")
+        self.assertEqual(chr(template_param_value.GetValueAsSigned()), 'v')
+
+        # FIXME: type should be Foo<float, 2.0f>
+        # FIXME: double/float NTTP parameter values currently not supported.
+        value = self.expect_expr("temp4", result_type="Foo<float, float>")
+        template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertFalse(template_param_value)
diff --git a/lldb/test/API/lang/cpp/template-arguments/main.cpp b/lldb/test/API/lang/cpp/template-arguments/main.cpp
index 728bd400c2586..0c0eb97cbc858 100644
--- a/lldb/test/API/lang/cpp/template-arguments/main.cpp
+++ b/lldb/test/API/lang/cpp/template-arguments/main.cpp
@@ -5,4 +5,9 @@ struct C {
 
 C<int, 2> temp1;
 
+template <typename T, T value> struct Foo {};
+Foo<short, -2> temp2;
+Foo<char, 'v'> temp3;
+Foo<float, 2.0f> temp4;
+
 int main() {}

>From 09205d7d4a28bfcecfb6bfe544c89cba34a6c4c6 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 12 Feb 2025 12:38:31 +0000
Subject: [PATCH 2/5] fixup! formatting

---
 lldb/source/API/SBType.cpp                                 | 7 +++----
 .../cpp/template-arguments/TestCppTemplateArguments.py     | 2 +-
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index 8d04e9650b781..bedddd4b4f14b 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -692,7 +692,7 @@ lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target,
   LLDB_INSTRUMENT_VA(this, target, idx);
 
   if (!IsValid())
-    return SBValue();
+    return {};
 
   std::optional<CompilerType::IntegralTemplateArgument> arg;
   const bool expand_pack = true;
@@ -716,9 +716,8 @@ lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target,
   DataExtractor data;
   value.GetData(data);
 
-  auto value_obj_sp = ValueObjectConstResult::Create(
-      target.GetSP().get(), arg->type, ConstString("value"), data);
-  return SBValue(std::move(value_obj_sp));
+  return SBValue(ValueObjectConstResult::Create(target.GetSP().get(), arg->type,
+                                                ConstString("value"), data));
 }
 
 SBType SBType::FindDirectNestedType(const char *name) {
diff --git a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
index eb5959c2a3668..f2c0a409d0980 100644
--- a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
+++ b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
@@ -55,7 +55,7 @@ def test(self):
         template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
         self.assertTrue(template_param_value)
         self.assertEqual(template_param_value.GetTypeName(), "char")
-        self.assertEqual(chr(template_param_value.GetValueAsSigned()), 'v')
+        self.assertEqual(chr(template_param_value.GetValueAsSigned()), "v")
 
         # FIXME: type should be Foo<float, 2.0f>
         # FIXME: double/float NTTP parameter values currently not supported.

>From 2ff8278dcff2b85be42cd890471ccb88bc19835f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 12 Feb 2025 13:20:36 +0000
Subject: [PATCH 3/5] fixup! use CreateValueObjectFromData; add test-case;
 remove redundant Scalar::IsValid check

---
 lldb/source/API/SBType.cpp                          | 13 ++++++++-----
 .../template-arguments/TestCppTemplateArguments.py  |  4 ++++
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index bedddd4b4f14b..6401d32c85795 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -709,15 +709,18 @@ lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target,
     return {};
 
   Scalar value{arg->value};
+  DataExtractor data;
+  value.GetData(data);
 
-  if (!value.IsValid())
+  ExecutionContext exe_ctx;
+  auto target_sp = target.GetSP();
+  if (!target_sp)
     return {};
 
-  DataExtractor data;
-  value.GetData(data);
+  target_sp->CalculateExecutionContext(exe_ctx);
 
-  return SBValue(ValueObjectConstResult::Create(target.GetSP().get(), arg->type,
-                                                ConstString("value"), data));
+  return ValueObject::CreateValueObjectFromData("value", data, exe_ctx,
+                                                arg->type);
 }
 
 SBType SBType::FindDirectNestedType(const char *name) {
diff --git a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
index f2c0a409d0980..f1b3d7a9806fd 100644
--- a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
+++ b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
@@ -46,6 +46,10 @@ def test(self):
         self.assertEqual(template_type.GetTemplateArgumentType(2).GetName(), "")
 
         value = self.expect_expr("temp2", result_type="Foo<short, -2>")
+
+        # Can't get template parameter value with invalid target.
+        self.assertFalse(value.GetType().GetTemplateArgumentValue(lldb.SBTarget(), 1))
+
         template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
         self.assertTrue(template_param_value)
         self.assertEqual(template_param_value.GetTypeName(), "short")

>From 882c0cbef43c116305e6be499ae02be2190b3f3d Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 12 Feb 2025 13:40:10 +0000
Subject: [PATCH 4/5] fixup! remove friend declarations

---
 lldb/include/lldb/API/SBTarget.h |  2 +-
 lldb/include/lldb/API/SBType.h   |  3 +++
 lldb/include/lldb/API/SBValue.h  |  3 ++-
 lldb/source/API/SBType.cpp       | 14 +++++++++++---
 4 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index bb912ab41d0fe..a3926d51e6f4a 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -964,7 +964,6 @@ class LLDB_API SBTarget {
   friend class SBSection;
   friend class SBSourceManager;
   friend class SBSymbol;
-  friend class SBType;
   friend class SBTypeStaticField;
   friend class SBValue;
   friend class SBVariablesOptions;
@@ -977,6 +976,7 @@ class LLDB_API SBTarget {
   SBTarget(const lldb::TargetSP &target_sp);
 
   lldb::TargetSP GetSP() const;
+  friend lldb::TargetSP lldb_private::GetUnderlying(SBTarget const &target);
 
   void SetSP(const lldb::TargetSP &target_sp);
 
diff --git a/lldb/include/lldb/API/SBType.h b/lldb/include/lldb/API/SBType.h
index 9ad3244686328..618764e2f9cd7 100644
--- a/lldb/include/lldb/API/SBType.h
+++ b/lldb/include/lldb/API/SBType.h
@@ -15,6 +15,9 @@ namespace lldb_private {
 namespace python {
 class SWIGBridge;
 }
+
+lldb::TargetSP GetUnderlying(const lldb::SBTarget &target);
+lldb::SBValue CreateSBValue(const lldb::ValueObjectSP &vo);
 } // namespace lldb_private
 
 namespace lldb {
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
index 46ef6daa95264..6b5314abd444e 100644
--- a/lldb/include/lldb/API/SBValue.h
+++ b/lldb/include/lldb/API/SBValue.h
@@ -446,7 +446,6 @@ class LLDB_API SBValue {
   friend class SBModule;
   friend class SBTarget;
   friend class SBThread;
-  friend class SBType;
   friend class SBTypeStaticField;
   friend class SBTypeSummary;
   friend class SBValueList;
@@ -455,6 +454,8 @@ class LLDB_API SBValue {
 
   SBValue(const lldb::ValueObjectSP &value_sp);
 
+  friend SBValue lldb_private::CreateSBValue(lldb::ValueObjectSP const &);
+
   /// Same as the protected version of GetSP that takes a locker, except that we
   /// make the
   /// locker locally in the function.  Since the Target API mutex is recursive,
diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index 6401d32c85795..83d47034b7497 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -33,6 +33,14 @@
 using namespace lldb;
 using namespace lldb_private;
 
+lldb::TargetSP lldb_private::GetUnderlying(const lldb::SBTarget &target) {
+  return target.GetSP();
+}
+
+lldb::SBValue lldb_private::CreateSBValue(const lldb::ValueObjectSP &vo) {
+  return lldb::SBValue(vo);
+}
+
 SBType::SBType() { LLDB_INSTRUMENT_VA(this); }
 
 SBType::SBType(const CompilerType &type) : m_opaque_sp(new TypeImpl(type)) {}
@@ -713,14 +721,14 @@ lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target,
   value.GetData(data);
 
   ExecutionContext exe_ctx;
-  auto target_sp = target.GetSP();
+  auto target_sp = GetUnderlying(target);
   if (!target_sp)
     return {};
 
   target_sp->CalculateExecutionContext(exe_ctx);
 
-  return ValueObject::CreateValueObjectFromData("value", data, exe_ctx,
-                                                arg->type);
+  return CreateSBValue(ValueObject::CreateValueObjectFromData("value", data, exe_ctx,
+                                                arg->type));
 }
 
 SBType SBType::FindDirectNestedType(const char *name) {

>From 6a2c0d3ca01b243de45ac2f516a5645dca3fbe4b Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 12 Feb 2025 13:45:48 +0000
Subject: [PATCH 5/5] fixup! clang-format

---
 lldb/source/API/SBType.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index 83d47034b7497..0716216af35a3 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -727,8 +727,8 @@ lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target,
 
   target_sp->CalculateExecutionContext(exe_ctx);
 
-  return CreateSBValue(ValueObject::CreateValueObjectFromData("value", data, exe_ctx,
-                                                arg->type));
+  return CreateSBValue(ValueObject::CreateValueObjectFromData(
+      "value", data, exe_ctx, arg->type));
 }
 
 SBType SBType::FindDirectNestedType(const char *name) {



More information about the lldb-commits mailing list