[Lldb-commits] [lldb] [lldb][Expression] Add API to set/get language-specific expression options (PR #179208)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Mon Feb 2 04:08:12 PST 2026
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/179208
>From 4adc40f712e657c71c7ac42160b18e9bedddafb9 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 2 Feb 2026 10:41:14 +0000
Subject: [PATCH 1/3] [lldb][Expression] Add API to set/get language-specific
expression options
The motivation here is that we don't want to pollute the SBAPI with getters/setters for expression evaluation options that only apply to a single language. The ultimate goal would be to have plugins register additional options to the `expression` command when the plugin is loaded. This patch only provides the minimal `SBExpressionOptions` interface to set an option with an arbitrary name, which the language plugin knows how to interpret. The underlying options dictionary is an `StructuredData::Dictionary` so we can map strings to values of any type. But the SBAPI just exposes setting a boolean value. Future overloads of `SetLanguageOption` can provide setters for more types.
The boolean setter/getter will be used for the C++-specific option being introduced in: https://github.com/llvm/llvm-project/pull/177926
---
.../interface/SBExpressionOptionsDocstrings.i | 6 +++
lldb/include/lldb/API/SBExpressionOptions.h | 5 +++
lldb/include/lldb/Target/Target.h | 42 ++++++++++++++++++-
lldb/source/API/SBExpressionOptions.cpp | 12 ++++++
.../expression/options/TestExprOptions.py | 25 ++++++++++-
lldb/unittests/Expression/ExpressionTest.cpp | 25 +++++++++++
6 files changed, 112 insertions(+), 3 deletions(-)
diff --git a/lldb/bindings/interface/SBExpressionOptionsDocstrings.i b/lldb/bindings/interface/SBExpressionOptionsDocstrings.i
index 2bb562778db79..a6de6f034bd7a 100644
--- a/lldb/bindings/interface/SBExpressionOptionsDocstrings.i
+++ b/lldb/bindings/interface/SBExpressionOptionsDocstrings.i
@@ -61,3 +61,9 @@
%feature("docstring", "Sets whether to JIT an expression if it cannot be interpreted."
) lldb::SBExpressionOptions::SetAllowJIT;
+
+%feature("docstring", "Sets language-plugin specific boolean option for expression evaluation."
+) lldb::SBExpressionOptions::SetLanguageOption;
+
+%feature("docstring", "Gets language-plugin specific boolean option for expression evaluation."
+) lldb::SBExpressionOptions::GetLanguageOptionAsBoolean;
diff --git a/lldb/include/lldb/API/SBExpressionOptions.h b/lldb/include/lldb/API/SBExpressionOptions.h
index a9e929a4c0bd9..6f7bd53d6fa70 100644
--- a/lldb/include/lldb/API/SBExpressionOptions.h
+++ b/lldb/include/lldb/API/SBExpressionOptions.h
@@ -11,6 +11,7 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBLanguages.h"
+#include "lldb/API/SBStructuredData.h"
#include <vector>
@@ -107,6 +108,10 @@ class LLDB_API SBExpressionOptions {
// Sets whether we will JIT an expression if it cannot be interpreted
void SetAllowJIT(bool allow);
+ bool GetLanguageOptionAsBoolean(const char *option_name) const;
+
+ void SetLanguageOption(const char *option_name, bool value);
+
protected:
lldb_private::EvaluateExpressionOptions *get() const;
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 812a638910b3b..2583c14965e61 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -15,6 +15,7 @@
#include <string>
#include <vector>
+#include "lldb/API/SBStructuredData.h"
#include "lldb/Breakpoint/BreakpointList.h"
#include "lldb/Breakpoint/BreakpointName.h"
#include "lldb/Breakpoint/WatchpointList.h"
@@ -307,6 +308,8 @@ class TargetProperties : public Properties {
class EvaluateExpressionOptions {
public:
+ EvaluateExpressionOptions() : m_language_options_sp(std::make_shared<StructuredData::Dictionary>()) {}
+
// MSVC has a bug here that reports C4268: 'const' static/global data
// initialized with compiler generated default constructor fills the object
// with zeros. Confirmed that MSVC is *not* zero-initializing, it's just a
@@ -323,8 +326,6 @@ class EvaluateExpressionOptions {
static constexpr ExecutionPolicy default_execution_policy =
eExecutionPolicyOnlyWhenNeeded;
- EvaluateExpressionOptions() = default;
-
ExecutionPolicy GetExecutionPolicy() const { return m_execution_policy; }
void SetExecutionPolicy(ExecutionPolicy policy = eExecutionPolicyAlways) {
@@ -481,7 +482,40 @@ class EvaluateExpressionOptions {
void SetIsForUtilityExpr(bool b) { m_running_utility_expression = b; }
+ /// Set language-plugin specific option called \c option_name to
+ /// the specified boolean \c value.
+ void SetLanguageOption(llvm::StringRef option_name, bool value) {
+ if (option_name.empty())
+ return;
+
+ GetLanguageOptions().AddBooleanItem(option_name, value);
+ }
+
+ /// Get the language-plugin specific boolean option called \c option_name.
+ ///
+ /// If the option doesn't exist or is not a boolean option, returns false.
+ /// Otherwise returns the boolean value of the option.
+ bool GetLanguageOptionAsBoolean(llvm::StringRef option_name) const {
+ bool result;
+ if (!GetLanguageOptions().GetValueForKeyAsBoolean(option_name, result))
+ return false;
+
+ return result;
+ }
+
private:
+ const StructuredData::Dictionary &GetLanguageOptions() const {
+ assert (m_language_options_sp);
+
+ return *m_language_options_sp;
+ }
+
+ StructuredData::Dictionary &GetLanguageOptions() {
+ assert (m_language_options_sp);
+
+ return *m_language_options_sp;
+ }
+
ExecutionPolicy m_execution_policy = default_execution_policy;
SourceLanguage m_language;
std::string m_prefix;
@@ -514,6 +548,10 @@ class EvaluateExpressionOptions {
mutable std::string m_pound_line_file;
mutable uint32_t m_pound_line_line = 0;
+ /// Dictionary mapping names of language-plugin specific options
+ /// to values.
+ StructuredData::DictionarySP m_language_options_sp = nullptr;
+
/// During expression evaluation, any SymbolContext in this list will be
/// used for symbol/function lookup before any other context (except for
/// the module corresponding to the current frame).
diff --git a/lldb/source/API/SBExpressionOptions.cpp b/lldb/source/API/SBExpressionOptions.cpp
index 15ed403eaaea1..e28c7ebfd0133 100644
--- a/lldb/source/API/SBExpressionOptions.cpp
+++ b/lldb/source/API/SBExpressionOptions.cpp
@@ -256,6 +256,18 @@ void SBExpressionOptions::SetAllowJIT(bool allow) {
: eExecutionPolicyNever);
}
+bool SBExpressionOptions::GetLanguageOptionAsBoolean(const char *option_name) const {
+ LLDB_INSTRUMENT_VA(this, option_name);
+
+ return m_opaque_up->GetLanguageOptionAsBoolean(option_name);
+}
+
+void SBExpressionOptions::SetLanguageOption(const char *option_name, bool value) {
+ LLDB_INSTRUMENT_VA(this, option_name, value);
+
+ m_opaque_up->SetLanguageOption(option_name, value);
+ }
+
EvaluateExpressionOptions *SBExpressionOptions::get() const {
return m_opaque_up.get();
}
diff --git a/lldb/test/API/commands/expression/options/TestExprOptions.py b/lldb/test/API/commands/expression/options/TestExprOptions.py
index 01899f3b97cf4..96bb4742a1a10 100644
--- a/lldb/test/API/commands/expression/options/TestExprOptions.py
+++ b/lldb/test/API/commands/expression/options/TestExprOptions.py
@@ -7,7 +7,6 @@
Test expression command options.
"""
-
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.decorators import *
@@ -85,3 +84,27 @@ def test_expr_options_lang(self):
val = frame.EvaluateExpression("id == 0", options)
self.assertTrue(val.IsValid())
self.assertFalse(val.GetError().Success())
+
+ def test_expr_options_language_options(self):
+ """Test SetLanguageOption/GetLanguageOption SBAPIs"""
+
+ options = lldb.SBExpressionOptions()
+ self.assertFalse(options.GetLanguageOptionAsBoolean("foo"))
+ self.assertFalse(options.GetLanguageOptionAsBoolean("bar"))
+
+ options.SetLanguageOption("foo", True)
+ options.SetLanguageOption("bar", True)
+ self.assertTrue(options.GetLanguageOptionAsBoolean("foo"))
+ self.assertTrue(options.GetLanguageOptionAsBoolean("bar"))
+
+ options.SetLanguageOption("foo", False)
+ options.SetLanguageOption("bar", False)
+ self.assertFalse(options.GetLanguageOptionAsBoolean("foo"))
+ self.assertFalse(options.GetLanguageOptionAsBoolean("bar"))
+
+ self.assertFalse(options.GetLanguageOptionAsBoolean(""))
+ options.SetLanguageOption("", True)
+ self.assertFalse(options.GetLanguageOptionAsBoolean(""))
+
+ options.SetLanguageOption(None, True)
+ self.assertFalse(options.GetLanguageOptionAsBoolean(None))
diff --git a/lldb/unittests/Expression/ExpressionTest.cpp b/lldb/unittests/Expression/ExpressionTest.cpp
index ceb567c28ab99..4201516dfc820 100644
--- a/lldb/unittests/Expression/ExpressionTest.cpp
+++ b/lldb/unittests/Expression/ExpressionTest.cpp
@@ -10,6 +10,7 @@
#include "gtest/gtest.h"
#include "TestingSupport/TestUtilities.h"
+#include "lldb/Target/Target.h"
#include "lldb/Expression/Expression.h"
#include "llvm/Testing/Support/Error.h"
@@ -127,3 +128,27 @@ TEST_P(ExpressionTestFixture, FunctionCallLabel) {
INSTANTIATE_TEST_SUITE_P(FunctionCallLabelTest, ExpressionTestFixture,
testing::ValuesIn(g_label_test_cases));
+
+TEST(ExpressionTests, ExpressionOptions_Basic) {
+ EvaluateExpressionOptions options;
+
+ ASSERT_FALSE(options.GetLanguageOptionAsBoolean("foo"));
+ ASSERT_FALSE(options.GetLanguageOptionAsBoolean("bar"));
+
+ options.SetLanguageOption("foo", true);
+ options.SetLanguageOption("bar", true);
+
+ ASSERT_TRUE(options.GetLanguageOptionAsBoolean("foo"));
+ ASSERT_TRUE(options.GetLanguageOptionAsBoolean("bar"));
+
+ options.SetLanguageOption("foo", false);
+ options.SetLanguageOption("bar", false);
+
+ ASSERT_FALSE(options.GetLanguageOptionAsBoolean("foo"));
+ ASSERT_FALSE(options.GetLanguageOptionAsBoolean("bar"));
+
+ // Empty option names not allowed.
+ ASSERT_FALSE(options.GetLanguageOptionAsBoolean(""));
+ options.SetLanguageOption("", true);
+ ASSERT_FALSE(options.GetLanguageOptionAsBoolean(""));
+}
>From f1d8205d7923773f343e54105c7f60300851e123 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 2 Feb 2026 11:25:33 +0000
Subject: [PATCH 2/3] fixup! clang-format
---
lldb/include/lldb/API/SBExpressionOptions.h | 2 +-
lldb/include/lldb/Target/Target.h | 7 ++++---
lldb/source/API/SBExpressionOptions.cpp | 8 +++++---
lldb/unittests/Expression/ExpressionTest.cpp | 2 +-
4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/lldb/include/lldb/API/SBExpressionOptions.h b/lldb/include/lldb/API/SBExpressionOptions.h
index 6f7bd53d6fa70..f0a37589fabe4 100644
--- a/lldb/include/lldb/API/SBExpressionOptions.h
+++ b/lldb/include/lldb/API/SBExpressionOptions.h
@@ -109,7 +109,7 @@ class LLDB_API SBExpressionOptions {
void SetAllowJIT(bool allow);
bool GetLanguageOptionAsBoolean(const char *option_name) const;
-
+
void SetLanguageOption(const char *option_name, bool value);
protected:
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 2583c14965e61..67581e745c3d4 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -308,7 +308,8 @@ class TargetProperties : public Properties {
class EvaluateExpressionOptions {
public:
- EvaluateExpressionOptions() : m_language_options_sp(std::make_shared<StructuredData::Dictionary>()) {}
+ EvaluateExpressionOptions()
+ : m_language_options_sp(std::make_shared<StructuredData::Dictionary>()) {}
// MSVC has a bug here that reports C4268: 'const' static/global data
// initialized with compiler generated default constructor fills the object
@@ -505,13 +506,13 @@ class EvaluateExpressionOptions {
private:
const StructuredData::Dictionary &GetLanguageOptions() const {
- assert (m_language_options_sp);
+ assert(m_language_options_sp);
return *m_language_options_sp;
}
StructuredData::Dictionary &GetLanguageOptions() {
- assert (m_language_options_sp);
+ assert(m_language_options_sp);
return *m_language_options_sp;
}
diff --git a/lldb/source/API/SBExpressionOptions.cpp b/lldb/source/API/SBExpressionOptions.cpp
index e28c7ebfd0133..98a55733fbc3c 100644
--- a/lldb/source/API/SBExpressionOptions.cpp
+++ b/lldb/source/API/SBExpressionOptions.cpp
@@ -256,17 +256,19 @@ void SBExpressionOptions::SetAllowJIT(bool allow) {
: eExecutionPolicyNever);
}
-bool SBExpressionOptions::GetLanguageOptionAsBoolean(const char *option_name) const {
+bool SBExpressionOptions::GetLanguageOptionAsBoolean(
+ const char *option_name) const {
LLDB_INSTRUMENT_VA(this, option_name);
return m_opaque_up->GetLanguageOptionAsBoolean(option_name);
}
-void SBExpressionOptions::SetLanguageOption(const char *option_name, bool value) {
+void SBExpressionOptions::SetLanguageOption(const char *option_name,
+ bool value) {
LLDB_INSTRUMENT_VA(this, option_name, value);
m_opaque_up->SetLanguageOption(option_name, value);
- }
+}
EvaluateExpressionOptions *SBExpressionOptions::get() const {
return m_opaque_up.get();
diff --git a/lldb/unittests/Expression/ExpressionTest.cpp b/lldb/unittests/Expression/ExpressionTest.cpp
index 4201516dfc820..8bf8b20bc5203 100644
--- a/lldb/unittests/Expression/ExpressionTest.cpp
+++ b/lldb/unittests/Expression/ExpressionTest.cpp
@@ -10,8 +10,8 @@
#include "gtest/gtest.h"
#include "TestingSupport/TestUtilities.h"
-#include "lldb/Target/Target.h"
#include "lldb/Expression/Expression.h"
+#include "lldb/Target/Target.h"
#include "llvm/Testing/Support/Error.h"
using namespace lldb_private;
>From e468faab2c9fdad045e7b479a7086bc9b39eab5e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 2 Feb 2026 12:08:01 +0000
Subject: [PATCH 3/3] fixup! remove redundant include
---
lldb/include/lldb/API/SBExpressionOptions.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/lldb/include/lldb/API/SBExpressionOptions.h b/lldb/include/lldb/API/SBExpressionOptions.h
index f0a37589fabe4..8ef4204c302c1 100644
--- a/lldb/include/lldb/API/SBExpressionOptions.h
+++ b/lldb/include/lldb/API/SBExpressionOptions.h
@@ -11,7 +11,6 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBLanguages.h"
-#include "lldb/API/SBStructuredData.h"
#include <vector>
More information about the lldb-commits
mailing list