1 //===-- ValueObjectSyntheticFilter.cpp ------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/ValueObject/ValueObjectSyntheticFilter.h"
11 #include "lldb/Core/Value.h"
12 #include "lldb/DataFormatters/TypeSynthetic.h"
13 #include "lldb/Target/ExecutionContext.h"
14 #include "lldb/Utility/ConstString.h"
15 #include "lldb/Utility/LLDBLog.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/Status.h"
18 #include "lldb/ValueObject/ValueObject.h"
20 #include "llvm/ADT/STLExtras.h"
23 namespace lldb_private
{
27 using namespace lldb_private
;
29 class DummySyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
31 DummySyntheticFrontEnd(ValueObject
&backend
)
32 : SyntheticChildrenFrontEnd(backend
) {}
34 llvm::Expected
<uint32_t> CalculateNumChildren() override
{
35 return m_backend
.GetNumChildren();
38 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx
) override
{
39 return m_backend
.GetChildAtIndex(idx
);
42 size_t GetIndexOfChildWithName(ConstString name
) override
{
43 return m_backend
.GetIndexOfChildWithName(name
);
46 bool MightHaveChildren() override
{ return m_backend
.MightHaveChildren(); }
48 lldb::ChildCacheState
Update() override
{
49 return lldb::ChildCacheState::eRefetch
;
53 ValueObjectSynthetic::ValueObjectSynthetic(ValueObject
&parent
,
54 lldb::SyntheticChildrenSP filter
)
55 : ValueObject(parent
), m_synth_sp(std::move(filter
)), m_children_byindex(),
56 m_name_toindex(), m_synthetic_children_cache(),
57 m_synthetic_children_count(UINT32_MAX
),
58 m_parent_type_name(parent
.GetTypeName()),
59 m_might_have_children(eLazyBoolCalculate
),
60 m_provides_value(eLazyBoolCalculate
) {
61 SetName(parent
.GetName());
62 // Copying the data of an incomplete type won't work as it has no byte size.
63 if (m_parent
->GetCompilerType().IsCompleteType())
64 CopyValueData(m_parent
);
68 ValueObjectSynthetic::~ValueObjectSynthetic() = default;
70 CompilerType
ValueObjectSynthetic::GetCompilerTypeImpl() {
71 return m_parent
->GetCompilerType();
74 ConstString
ValueObjectSynthetic::GetTypeName() {
75 return m_parent
->GetTypeName();
78 ConstString
ValueObjectSynthetic::GetQualifiedTypeName() {
79 return m_parent
->GetQualifiedTypeName();
82 ConstString
ValueObjectSynthetic::GetDisplayTypeName() {
83 if (ConstString synth_name
= m_synth_filter_up
->GetSyntheticTypeName())
86 return m_parent
->GetDisplayTypeName();
89 llvm::Expected
<uint32_t>
90 ValueObjectSynthetic::CalculateNumChildren(uint32_t max
) {
91 Log
*log
= GetLog(LLDBLog::DataFormatters
);
93 UpdateValueIfNeeded();
94 if (m_synthetic_children_count
< UINT32_MAX
)
95 return m_synthetic_children_count
<= max
? m_synthetic_children_count
: max
;
97 if (max
< UINT32_MAX
) {
98 auto num_children
= m_synth_filter_up
->CalculateNumChildren(max
);
100 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
101 "%s and type %s, the filter returned %u child values",
102 GetName().AsCString(), GetTypeName().AsCString(),
103 num_children
? *num_children
: 0);
106 auto num_children_or_err
= m_synth_filter_up
->CalculateNumChildren(max
);
107 if (!num_children_or_err
) {
108 m_synthetic_children_count
= 0;
109 return num_children_or_err
;
111 auto num_children
= (m_synthetic_children_count
= *num_children_or_err
);
113 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
114 "%s and type %s, the filter returned %u child values",
115 GetName().AsCString(), GetTypeName().AsCString(), num_children
);
121 ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType
) {
123 return lldb::ValueObjectSP();
124 if (IsDynamic() && GetDynamicValueType() == valueType
)
126 return m_parent
->GetDynamicValue(valueType
);
129 bool ValueObjectSynthetic::MightHaveChildren() {
130 if (m_might_have_children
== eLazyBoolCalculate
)
131 m_might_have_children
=
132 (m_synth_filter_up
->MightHaveChildren() ? eLazyBoolYes
: eLazyBoolNo
);
133 return (m_might_have_children
!= eLazyBoolNo
);
136 std::optional
<uint64_t> ValueObjectSynthetic::GetByteSize() {
137 return m_parent
->GetByteSize();
140 lldb::ValueType
ValueObjectSynthetic::GetValueType() const {
141 return m_parent
->GetValueType();
144 void ValueObjectSynthetic::CreateSynthFilter() {
145 ValueObject
*valobj_for_frontend
= m_parent
;
146 if (m_synth_sp
->WantsDereference()) {
147 CompilerType type
= m_parent
->GetCompilerType();
148 if (type
.IsValid() && type
.IsPointerOrReferenceType()) {
150 lldb::ValueObjectSP deref_sp
= m_parent
->Dereference(error
);
152 valobj_for_frontend
= deref_sp
.get();
155 m_synth_filter_up
= (m_synth_sp
->GetFrontEnd(*valobj_for_frontend
));
156 if (!m_synth_filter_up
)
157 m_synth_filter_up
= std::make_unique
<DummySyntheticFrontEnd
>(*m_parent
);
160 bool ValueObjectSynthetic::UpdateValue() {
161 Log
*log
= GetLog(LLDBLog::DataFormatters
);
163 SetValueIsValid(false);
166 if (!m_parent
->UpdateValueIfNeeded(false)) {
167 // our parent could not update.. as we are meaningless without a parent,
169 if (m_parent
->GetError().Fail())
170 m_error
= m_parent
->GetError().Clone();
174 // Regenerate the synthetic filter if our typename changes. When the (dynamic)
175 // type of an object changes, so does their synthetic filter of choice.
176 ConstString new_parent_type_name
= m_parent
->GetTypeName();
177 if (new_parent_type_name
!= m_parent_type_name
) {
179 "[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
180 "from %s to %s, recomputing synthetic filter",
181 GetName().AsCString(), m_parent_type_name
.AsCString(),
182 new_parent_type_name
.AsCString());
183 m_parent_type_name
= new_parent_type_name
;
187 // let our backend do its update
188 if (m_synth_filter_up
->Update() == lldb::ChildCacheState::eRefetch
) {
190 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
191 "filter said caches are stale - clearing",
192 GetName().AsCString());
193 // filter said that cached values are stale
195 std::lock_guard
<std::mutex
> guard(m_child_mutex
);
196 m_children_byindex
.clear();
197 m_name_toindex
.clear();
199 // usually, an object's value can change but this does not alter its
200 // children count for a synthetic VO that might indeed happen, so we need
201 // to tell the upper echelons that they need to come back to us asking for
203 m_flags
.m_children_count_valid
= false;
205 std::lock_guard
<std::mutex
> guard(m_child_mutex
);
206 m_synthetic_children_cache
.clear();
208 m_synthetic_children_count
= UINT32_MAX
;
209 m_might_have_children
= eLazyBoolCalculate
;
212 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
213 "filter said caches are still valid",
214 GetName().AsCString());
217 m_provides_value
= eLazyBoolCalculate
;
219 lldb::ValueObjectSP
synth_val(m_synth_filter_up
->GetSyntheticValue());
221 if (synth_val
&& synth_val
->CanProvideValue()) {
223 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
224 "filter said it can provide a value",
225 GetName().AsCString());
227 m_provides_value
= eLazyBoolYes
;
228 CopyValueData(synth_val
.get());
231 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
232 "filter said it will not provide a value",
233 GetName().AsCString());
235 m_provides_value
= eLazyBoolNo
;
236 // Copying the data of an incomplete type won't work as it has no byte size.
237 if (m_parent
->GetCompilerType().IsCompleteType())
238 CopyValueData(m_parent
);
241 SetValueIsValid(true);
245 lldb::ValueObjectSP
ValueObjectSynthetic::GetChildAtIndex(uint32_t idx
,
247 Log
*log
= GetLog(LLDBLog::DataFormatters
);
250 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
252 GetName().AsCString(), idx
);
254 UpdateValueIfNeeded();
257 bool child_is_cached
;
259 std::lock_guard
<std::mutex
> guard(m_child_mutex
);
260 auto cached_child_it
= m_children_byindex
.find(idx
);
261 child_is_cached
= cached_child_it
!= m_children_byindex
.end();
263 valobj
= cached_child_it
->second
;
266 if (!child_is_cached
) {
267 if (can_create
&& m_synth_filter_up
!= nullptr) {
269 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
270 "index %u not cached and will be created",
271 GetName().AsCString(), idx
);
273 lldb::ValueObjectSP synth_guy
= m_synth_filter_up
->GetChildAtIndex(idx
);
277 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
278 "%u created as %p (is "
280 GetName().AsCString(), idx
, static_cast<void *>(synth_guy
.get()),
282 ? (synth_guy
->IsSyntheticChildrenGenerated() ? "yes" : "no")
289 std::lock_guard
<std::mutex
> guard(m_child_mutex
);
290 if (synth_guy
->IsSyntheticChildrenGenerated())
291 m_synthetic_children_cache
.push_back(synth_guy
);
292 m_children_byindex
[idx
] = synth_guy
.get();
294 synth_guy
->SetPreferredDisplayLanguageIfNeeded(
295 GetPreferredDisplayLanguage());
299 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
300 "index %u not cached and cannot "
301 "be created (can_create = %s, synth_filter = %p)",
302 GetName().AsCString(), idx
, can_create
? "yes" : "no",
303 static_cast<void *>(m_synth_filter_up
.get()));
305 return lldb::ValueObjectSP();
309 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
310 "index %u cached as %p",
311 GetName().AsCString(), idx
, static_cast<void *>(valobj
));
313 return valobj
->GetSP();
318 ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name
,
320 UpdateValueIfNeeded();
322 uint32_t index
= GetIndexOfChildWithName(name
);
324 if (index
== UINT32_MAX
)
325 return lldb::ValueObjectSP();
327 return GetChildAtIndex(index
, can_create
);
330 size_t ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref
) {
331 UpdateValueIfNeeded();
333 ConstString
name(name_ref
);
335 uint32_t found_index
= UINT32_MAX
;
338 std::lock_guard
<std::mutex
> guard(m_child_mutex
);
339 auto name_to_index
= m_name_toindex
.find(name
.GetCString());
340 did_find
= name_to_index
!= m_name_toindex
.end();
342 found_index
= name_to_index
->second
;
345 if (!did_find
&& m_synth_filter_up
!= nullptr) {
346 uint32_t index
= m_synth_filter_up
->GetIndexOfChildWithName(name
);
347 if (index
== UINT32_MAX
)
349 std::lock_guard
<std::mutex
> guard(m_child_mutex
);
350 m_name_toindex
[name
.GetCString()] = index
;
352 } else if (!did_find
&& m_synth_filter_up
== nullptr)
354 else /*if (iter != m_name_toindex.end())*/
358 bool ValueObjectSynthetic::IsInScope() { return m_parent
->IsInScope(); }
360 lldb::ValueObjectSP
ValueObjectSynthetic::GetNonSyntheticValue() {
361 return m_parent
->GetSP();
364 void ValueObjectSynthetic::CopyValueData(ValueObject
*source
) {
365 m_value
= (source
->UpdateValueIfNeeded(), source
->GetValue());
366 ExecutionContext
exe_ctx(GetExecutionContextRef());
367 m_error
= m_value
.GetValueAsData(&exe_ctx
, m_data
, GetModule().get());
370 bool ValueObjectSynthetic::CanProvideValue() {
371 if (!UpdateValueIfNeeded())
373 if (m_provides_value
== eLazyBoolYes
)
375 return m_parent
->CanProvideValue();
378 bool ValueObjectSynthetic::SetValueFromCString(const char *value_str
,
380 return m_parent
->SetValueFromCString(value_str
, error
);
383 void ValueObjectSynthetic::SetFormat(lldb::Format format
) {
385 m_parent
->ClearUserVisibleData(eClearUserVisibleDataItemsAll
);
386 m_parent
->SetFormat(format
);
388 this->ValueObject::SetFormat(format
);
389 this->ClearUserVisibleData(eClearUserVisibleDataItemsAll
);
392 void ValueObjectSynthetic::SetPreferredDisplayLanguage(
393 lldb::LanguageType lang
) {
394 this->ValueObject::SetPreferredDisplayLanguage(lang
);
396 m_parent
->SetPreferredDisplayLanguage(lang
);
399 lldb::LanguageType
ValueObjectSynthetic::GetPreferredDisplayLanguage() {
400 if (m_preferred_display_language
== lldb::eLanguageTypeUnknown
) {
402 return m_parent
->GetPreferredDisplayLanguage();
403 return lldb::eLanguageTypeUnknown
;
405 return m_preferred_display_language
;
408 bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
410 return m_parent
->IsSyntheticChildrenGenerated();
414 void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b
) {
416 m_parent
->SetSyntheticChildrenGenerated(b
);
417 this->ValueObject::SetSyntheticChildrenGenerated(b
);
420 bool ValueObjectSynthetic::GetDeclaration(Declaration
&decl
) {
422 return m_parent
->GetDeclaration(decl
);
424 return ValueObject::GetDeclaration(decl
);
427 uint64_t ValueObjectSynthetic::GetLanguageFlags() {
429 return m_parent
->GetLanguageFlags();
430 return this->ValueObject::GetLanguageFlags();
433 void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags
) {
435 m_parent
->SetLanguageFlags(flags
);
437 this->ValueObject::SetLanguageFlags(flags
);