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/Core/ValueObjectSyntheticFilter.h"
11 #include "lldb/Core/Value.h"
12 #include "lldb/Core/ValueObject.h"
13 #include "lldb/DataFormatters/TypeSynthetic.h"
14 #include "lldb/Target/ExecutionContext.h"
15 #include "lldb/Utility/Log.h"
16 #include "lldb/Utility/Logging.h"
17 #include "lldb/Utility/Status.h"
19 #include "llvm/ADT/STLExtras.h"
21 namespace lldb_private {
25 using namespace lldb_private;
27 class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
29 DummySyntheticFrontEnd(ValueObject &backend)
30 : SyntheticChildrenFrontEnd(backend) {}
32 size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); }
34 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
35 return m_backend.GetChildAtIndex(idx, true);
38 size_t GetIndexOfChildWithName(ConstString name) override {
39 return m_backend.GetIndexOfChildWithName(name);
42 bool MightHaveChildren() override { return true; }
44 bool Update() override { return false; }
47 ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
48 lldb::SyntheticChildrenSP filter)
49 : ValueObject(parent), m_synth_sp(filter), m_children_byindex(),
50 m_name_toindex(), m_synthetic_children_cache(),
51 m_synthetic_children_count(UINT32_MAX),
52 m_parent_type_name(parent.GetTypeName()),
53 m_might_have_children(eLazyBoolCalculate),
54 m_provides_value(eLazyBoolCalculate) {
55 SetName(parent.GetName());
56 // Copying the data of an incomplete type won't work as it has no byte size.
57 if (m_parent->GetCompilerType().IsCompleteType())
58 CopyValueData(m_parent);
62 ValueObjectSynthetic::~ValueObjectSynthetic() = default;
64 CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {
65 return m_parent->GetCompilerType();
68 ConstString ValueObjectSynthetic::GetTypeName() {
69 return m_parent->GetTypeName();
72 ConstString ValueObjectSynthetic::GetQualifiedTypeName() {
73 return m_parent->GetQualifiedTypeName();
76 ConstString ValueObjectSynthetic::GetDisplayTypeName() {
77 if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())
80 return m_parent->GetDisplayTypeName();
83 size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {
84 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
86 UpdateValueIfNeeded();
87 if (m_synthetic_children_count < UINT32_MAX)
88 return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
90 if (max < UINT32_MAX) {
91 size_t num_children = m_synth_filter_up->CalculateNumChildren(max);
93 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
94 "%s and type %s, the filter returned %zu child values",
95 GetName().AsCString(), GetTypeName().AsCString(), num_children);
98 size_t num_children = (m_synthetic_children_count =
99 m_synth_filter_up->CalculateNumChildren(max));
101 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
102 "%s and type %s, the filter returned %zu child values",
103 GetName().AsCString(), GetTypeName().AsCString(), num_children);
109 ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
111 return lldb::ValueObjectSP();
112 if (IsDynamic() && GetDynamicValueType() == valueType)
114 return m_parent->GetDynamicValue(valueType);
117 bool ValueObjectSynthetic::MightHaveChildren() {
118 if (m_might_have_children == eLazyBoolCalculate)
119 m_might_have_children =
120 (m_synth_filter_up->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
121 return (m_might_have_children != eLazyBoolNo);
124 uint64_t ValueObjectSynthetic::GetByteSize() { return m_parent->GetByteSize(); }
126 lldb::ValueType ValueObjectSynthetic::GetValueType() const {
127 return m_parent->GetValueType();
130 void ValueObjectSynthetic::CreateSynthFilter() {
131 ValueObject *valobj_for_frontend = m_parent;
132 if (m_synth_sp->WantsDereference())
134 CompilerType type = m_parent->GetCompilerType();
135 if (type.IsValid() && type.IsPointerOrReferenceType())
138 lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
140 valobj_for_frontend = deref_sp.get();
143 m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
144 if (!m_synth_filter_up)
145 m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);
148 bool ValueObjectSynthetic::UpdateValue() {
149 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
151 SetValueIsValid(false);
154 if (!m_parent->UpdateValueIfNeeded(false)) {
155 // our parent could not update.. as we are meaningless without a parent,
157 if (m_parent->GetError().Fail())
158 m_error = m_parent->GetError();
162 // regenerate the synthetic filter if our typename changes
163 // <rdar://problem/12424824>
164 ConstString new_parent_type_name = m_parent->GetTypeName();
165 if (new_parent_type_name != m_parent_type_name) {
167 "[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
168 "from %s to %s, recomputing synthetic filter",
169 GetName().AsCString(), m_parent_type_name.AsCString(),
170 new_parent_type_name.AsCString());
171 m_parent_type_name = new_parent_type_name;
175 // let our backend do its update
176 if (!m_synth_filter_up->Update()) {
178 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
179 "filter said caches are stale - clearing",
180 GetName().AsCString());
181 // filter said that cached values are stale
183 std::lock_guard<std::mutex> guard(m_child_mutex);
184 m_children_byindex.clear();
185 m_name_toindex.clear();
187 // usually, an object's value can change but this does not alter its
188 // children count for a synthetic VO that might indeed happen, so we need
189 // to tell the upper echelons that they need to come back to us asking for
191 m_children_count_valid = false;
193 std::lock_guard<std::mutex> guard(m_child_mutex);
194 m_synthetic_children_cache.clear();
196 m_synthetic_children_count = UINT32_MAX;
197 m_might_have_children = eLazyBoolCalculate;
200 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
201 "filter said caches are still valid",
202 GetName().AsCString());
205 m_provides_value = eLazyBoolCalculate;
207 lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());
209 if (synth_val && synth_val->CanProvideValue()) {
211 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
212 "filter said it can provide a value",
213 GetName().AsCString());
215 m_provides_value = eLazyBoolYes;
216 CopyValueData(synth_val.get());
219 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
220 "filter said it will not provide a value",
221 GetName().AsCString());
223 m_provides_value = eLazyBoolNo;
224 // Copying the data of an incomplete type won't work as it has no byte size.
225 if (m_parent->GetCompilerType().IsCompleteType())
226 CopyValueData(m_parent);
229 SetValueIsValid(true);
233 lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
235 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
238 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
239 "child at index %zu",
240 GetName().AsCString(), idx);
242 UpdateValueIfNeeded();
245 bool child_is_cached;
247 std::lock_guard<std::mutex> guard(m_child_mutex);
248 auto cached_child_it = m_children_byindex.find(idx);
249 child_is_cached = cached_child_it != m_children_byindex.end();
251 valobj = cached_child_it->second;
254 if (!child_is_cached) {
255 if (can_create && m_synth_filter_up != nullptr) {
257 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
258 "index %zu not cached and will be created",
259 GetName().AsCString(), idx);
261 lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);
265 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
266 "%zu created as %p (is "
268 GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
270 ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
277 std::lock_guard<std::mutex> guard(m_child_mutex);
278 if (synth_guy->IsSyntheticChildrenGenerated())
279 m_synthetic_children_cache.push_back(synth_guy);
280 m_children_byindex[idx] = synth_guy.get();
282 synth_guy->SetPreferredDisplayLanguageIfNeeded(
283 GetPreferredDisplayLanguage());
287 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
288 "index %zu not cached and cannot "
289 "be created (can_create = %s, synth_filter = %p)",
290 GetName().AsCString(), idx, can_create ? "yes" : "no",
291 static_cast<void *>(m_synth_filter_up.get()));
293 return lldb::ValueObjectSP();
297 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
298 "index %zu cached as %p",
299 GetName().AsCString(), idx, static_cast<void *>(valobj));
301 return valobj->GetSP();
306 ValueObjectSynthetic::GetChildMemberWithName(ConstString name,
308 UpdateValueIfNeeded();
310 uint32_t index = GetIndexOfChildWithName(name);
312 if (index == UINT32_MAX)
313 return lldb::ValueObjectSP();
315 return GetChildAtIndex(index, can_create);
318 size_t ValueObjectSynthetic::GetIndexOfChildWithName(ConstString name) {
319 UpdateValueIfNeeded();
321 uint32_t found_index = UINT32_MAX;
324 std::lock_guard<std::mutex> guard(m_child_mutex);
325 auto name_to_index = m_name_toindex.find(name.GetCString());
326 did_find = name_to_index != m_name_toindex.end();
328 found_index = name_to_index->second;
331 if (!did_find && m_synth_filter_up != nullptr) {
332 uint32_t index = m_synth_filter_up->GetIndexOfChildWithName(name);
333 if (index == UINT32_MAX)
335 std::lock_guard<std::mutex> guard(m_child_mutex);
336 m_name_toindex[name.GetCString()] = index;
338 } else if (!did_find && m_synth_filter_up == nullptr)
340 else /*if (iter != m_name_toindex.end())*/
344 bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
346 lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
347 return m_parent->GetSP();
350 void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
351 m_value = (source->UpdateValueIfNeeded(), source->GetValue());
352 ExecutionContext exe_ctx(GetExecutionContextRef());
353 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
356 bool ValueObjectSynthetic::CanProvideValue() {
357 if (!UpdateValueIfNeeded())
359 if (m_provides_value == eLazyBoolYes)
361 return m_parent->CanProvideValue();
364 bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
366 return m_parent->SetValueFromCString(value_str, error);
369 void ValueObjectSynthetic::SetFormat(lldb::Format format) {
371 m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
372 m_parent->SetFormat(format);
374 this->ValueObject::SetFormat(format);
375 this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
378 void ValueObjectSynthetic::SetPreferredDisplayLanguage(
379 lldb::LanguageType lang) {
380 this->ValueObject::SetPreferredDisplayLanguage(lang);
382 m_parent->SetPreferredDisplayLanguage(lang);
385 lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
386 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
388 return m_parent->GetPreferredDisplayLanguage();
389 return lldb::eLanguageTypeUnknown;
391 return m_preferred_display_language;
394 bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
396 return m_parent->IsSyntheticChildrenGenerated();
400 void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
402 m_parent->SetSyntheticChildrenGenerated(b);
403 this->ValueObject::SetSyntheticChildrenGenerated(b);
406 bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
408 return m_parent->GetDeclaration(decl);
410 return ValueObject::GetDeclaration(decl);
413 uint64_t ValueObjectSynthetic::GetLanguageFlags() {
415 return m_parent->GetLanguageFlags();
416 return this->ValueObject::GetLanguageFlags();
419 void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
421 m_parent->SetLanguageFlags(flags);
423 this->ValueObject::SetLanguageFlags(flags);