Files
llvm-project/lldb/source/ValueObject/ValueObjectSynthesizedValue.cpp
Med Ismail Bennani bb651180e3 [lldb] Report a scripted frame's variables with the frame's value type (#221708)
A scripted frame's variable exists as two objects: a Variable holding
the scope the frame assigned it, and a ValueObject holding what the
frame built. SBValue::GetValueType() reports the ValueObject's, and
GetValueObjectForFrameVariable handed that ValueObject back unchanged,
so the scope never reached a client. A ValueObject built in Python is a
ValueObjectConstResult, which reports how it was produced rather than
which variable it stands for, leaving anything that groups a frame's
variables by scope unable to place it. `frame variable` was unaffected
because it reads the Variables directly.

This patch presents the ValueObject under that scope instead. A class
for this already existed as ValueObjectRecognizerSynthesizedValue, which
frame recognizers use to name an argument: both take a ValueObject that
cannot report the ValueType it is being presented as and supply that
ValueType for it, so generalize that one into
ValueObjectSynthesizedValue and use it for both. ValueObjectVariable is
the other class that pairs a ValueObject with a ValueType, but it cannot
serve here because it recovers its data from a DWARF location
expression, and a frame that builds its own ValueObjects supplies none.

The presented ValueObject is not a parent, so it is no longer held as
one. It is the same ValueObject seen differently, which makes the
presenting object a root: constructing it as one keeps GetParent()
reporting no parent, as it does for any other ValueObject obtained from
a frame, and keeps the walks over m_parent (for a symbol context scope,
a root, a dynamic ValueObject or format information) from finding a
container that does not exist.

Recognized arguments change behaviour slightly as a result: the shared
UpdateValue propagates an error from the presented ValueObject, fills in
the data and sets validity, none of which the recognizer's copy did.

Reaching a variable by name goes through Variable::NameMatches, which
dereferences m_owner_scope for every entry whose name does not match. A
null owner scope is a legal state, CalculateSymbolContext handles it
explicitly and a frame that makes up its own variables has none, so drop
that lookup. The SymbolContext it filled in has had no reader since
22b044877d, which dropped the language argument to
Mangled::NameMatches along with the only use of it.

Also document that the synthetic flag in GetValueTypeForVariable's
return is what exempts a variable from the scope rules a declared
variable is subject to. A ValueObject with no storage behind it is
filtered out of an in-scope-only listing without it.

Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2026-09-16 01:53:02 +00:00

72 lines
2.4 KiB
C++

//===-- ValueObjectSynthesizedValue.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/ValueObject/ValueObjectSynthesizedValue.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
lldb::ValueObjectSP ValueObjectSynthesizedValue::Create(ValueObject &valobj,
lldb::ValueType type) {
ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
auto manager_sp = ValueObjectManager::Create();
return (new ValueObjectSynthesizedValue(
exe_ctx.GetBestExecutionContextScope(), *manager_sp,
valobj.GetSP(), type))
->GetSP();
}
ValueObjectSynthesizedValue::ValueObjectSynthesizedValue(
ExecutionContextScope *exe_scope, ValueObjectManager &manager,
const lldb::ValueObjectSP &valobj_sp, lldb::ValueType type)
: ValueObject(exe_scope, manager), m_valobj_sp(valobj_sp), m_type(type) {
SetName(valobj_sp->GetName());
}
ValueObjectSynthesizedValue::~ValueObjectSynthesizedValue() = default;
llvm::Expected<uint64_t> ValueObjectSynthesizedValue::GetByteSize() {
return m_valobj_sp->GetByteSize();
}
llvm::Expected<uint32_t>
ValueObjectSynthesizedValue::CalculateNumChildren(uint32_t max) {
return m_valobj_sp->GetNumChildren(max);
}
bool ValueObjectSynthesizedValue::IsInScope() {
return m_valobj_sp->IsInScope();
}
CompilerType ValueObjectSynthesizedValue::GetCompilerTypeImpl() {
return m_valobj_sp->GetCompilerType();
}
bool ValueObjectSynthesizedValue::UpdateValue() {
SetValueIsValid(false);
m_error.Clear();
if (!m_valobj_sp->UpdateValueIfNeeded(false)) {
if (m_error.Success() && m_valobj_sp->GetError().Fail())
m_error = m_valobj_sp->GetError().Clone();
return false;
}
m_update_point.SetUpdated();
m_value = m_valobj_sp->GetValue();
SetAddressTypeOfChildren(m_valobj_sp->GetAddressTypeOfChildren());
ExecutionContext exe_ctx(GetExecutionContextRef());
m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
SetValueDidChange(m_valobj_sp->GetValueDidChange());
SetValueIsValid(m_error.Success());
return m_error.Success();
}