1 //===-- ValueObjectSyntheticFilter.cpp --------------------------*- C++ -*-===//
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/SharingPtr.h"
18 #include "lldb/Utility/Status.h"
20 #include "llvm/ADT/STLExtras.h"
22 namespace lldb_private {
26 using namespace lldb_private;
28 class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
30 DummySyntheticFrontEnd(ValueObject &backend)
31 : SyntheticChildrenFrontEnd(backend) {}
33 size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); }
35 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
36 return m_backend.GetChildAtIndex(idx, true);
39 size_t GetIndexOfChildWithName(ConstString name) override {
40 return m_backend.GetIndexOfChildWithName(name);
43 bool MightHaveChildren() override { return true; }
45 bool Update() override { return false; }
48 ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
49 lldb::SyntheticChildrenSP filter)
50 : ValueObject(parent), m_synth_sp(filter), m_children_byindex(),
51 m_name_toindex(), m_synthetic_children_cache(),
52 m_synthetic_children_count(UINT32_MAX),
53 m_parent_type_name(parent.GetTypeName()),
54 m_might_have_children(eLazyBoolCalculate),
55 m_provides_value(eLazyBoolCalculate) {
56 SetName(parent.GetName());
57 CopyValueData(m_parent);
61 ValueObjectSynthetic::~ValueObjectSynthetic() = default;
63 CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {
64 return m_parent->GetCompilerType();
67 ConstString ValueObjectSynthetic::GetTypeName() {
68 return m_parent->GetTypeName();
71 ConstString ValueObjectSynthetic::GetQualifiedTypeName() {
72 return m_parent->GetQualifiedTypeName();
75 ConstString ValueObjectSynthetic::GetDisplayTypeName() {
76 if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())
79 return m_parent->GetDisplayTypeName();
82 size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {
83 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
85 UpdateValueIfNeeded();
86 if (m_synthetic_children_count < UINT32_MAX)
87 return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
89 if (max < UINT32_MAX) {
90 size_t num_children = m_synth_filter_up->CalculateNumChildren(max);
92 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
93 "%s and type %s, the filter returned %zu child values",
94 GetName().AsCString(), GetTypeName().AsCString(), num_children);
97 size_t num_children = (m_synthetic_children_count =
98 m_synth_filter_up->CalculateNumChildren(max));
100 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
101 "%s and type %s, the filter returned %zu child values",
102 GetName().AsCString(), GetTypeName().AsCString(), num_children);
108 ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
110 return lldb::ValueObjectSP();
111 if (IsDynamic() && GetDynamicValueType() == valueType)
113 return m_parent->GetDynamicValue(valueType);
116 bool ValueObjectSynthetic::MightHaveChildren() {
117 if (m_might_have_children == eLazyBoolCalculate)
118 m_might_have_children =
119 (m_synth_filter_up->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
120 return (m_might_have_children != eLazyBoolNo);
123 uint64_t ValueObjectSynthetic::GetByteSize() { return m_parent->GetByteSize(); }
125 lldb::ValueType ValueObjectSynthetic::GetValueType() const {
126 return m_parent->GetValueType();
129 void ValueObjectSynthetic::CreateSynthFilter() {
130 ValueObject *valobj_for_frontend = m_parent;
131 if (m_synth_sp->WantsDereference())
133 CompilerType type = m_parent->GetCompilerType();
134 if (type.IsValid() && type.IsPointerOrReferenceType())
137 lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
139 valobj_for_frontend = deref_sp.get();
142 m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
143 if (!m_synth_filter_up)
144 m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);
147 bool ValueObjectSynthetic::UpdateValue() {
148 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
150 SetValueIsValid(false);
153 if (!m_parent->UpdateValueIfNeeded(false)) {
154 // our parent could not update.. as we are meaningless without a parent,
156 if (m_parent->GetError().Fail())
157 m_error = m_parent->GetError();
161 // regenerate the synthetic filter if our typename changes
162 // <rdar://problem/12424824>
163 ConstString new_parent_type_name = m_parent->GetTypeName();
164 if (new_parent_type_name != m_parent_type_name) {
166 "[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
167 "from %s to %s, recomputing synthetic filter",
168 GetName().AsCString(), m_parent_type_name.AsCString(),
169 new_parent_type_name.AsCString());
170 m_parent_type_name = new_parent_type_name;
174 // let our backend do its update
175 if (!m_synth_filter_up->Update()) {
177 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
178 "filter said caches are stale - clearing",
179 GetName().AsCString());
180 // filter said that cached values are stale
182 std::lock_guard<std::mutex> guard(m_child_mutex);
183 m_children_byindex.clear();
184 m_name_toindex.clear();
186 // usually, an object's value can change but this does not alter its
187 // children count for a synthetic VO that might indeed happen, so we need
188 // to tell the upper echelons that they need to come back to us asking for
190 m_children_count_valid = false;
192 std::lock_guard<std::mutex> guard(m_child_mutex);
193 m_synthetic_children_cache.clear();
195 m_synthetic_children_count = UINT32_MAX;
196 m_might_have_children = eLazyBoolCalculate;
199 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
200 "filter said caches are still valid",
201 GetName().AsCString());
204 m_provides_value = eLazyBoolCalculate;
206 lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());
208 if (synth_val && synth_val->CanProvideValue()) {
210 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
211 "filter said it can provide a value",
212 GetName().AsCString());
214 m_provides_value = eLazyBoolYes;
215 CopyValueData(synth_val.get());
218 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
219 "filter said it will not provide a value",
220 GetName().AsCString());
222 m_provides_value = eLazyBoolNo;
223 CopyValueData(m_parent);
226 SetValueIsValid(true);
230 lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
232 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
235 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
236 "child at index %zu",
237 GetName().AsCString(), idx);
239 UpdateValueIfNeeded();
242 bool child_is_cached;
244 std::lock_guard<std::mutex> guard(m_child_mutex);
245 auto cached_child_it = m_children_byindex.find(idx);
246 child_is_cached = cached_child_it != m_children_byindex.end();
248 valobj = cached_child_it->second;
251 if (!child_is_cached) {
252 if (can_create && m_synth_filter_up != nullptr) {
254 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
255 "index %zu not cached and will be created",
256 GetName().AsCString(), idx);
258 lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);
262 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
263 "%zu created as %p (is "
265 GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
267 ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
274 std::lock_guard<std::mutex> guard(m_child_mutex);
275 if (synth_guy->IsSyntheticChildrenGenerated())
276 m_synthetic_children_cache.push_back(synth_guy);
277 m_children_byindex[idx] = synth_guy.get();
279 synth_guy->SetPreferredDisplayLanguageIfNeeded(
280 GetPreferredDisplayLanguage());
284 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
285 "index %zu not cached and cannot "
286 "be created (can_create = %s, synth_filter = %p)",
287 GetName().AsCString(), idx, can_create ? "yes" : "no",
288 static_cast<void *>(m_synth_filter_up.get()));
290 return lldb::ValueObjectSP();
294 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
295 "index %zu cached as %p",
296 GetName().AsCString(), idx, static_cast<void *>(valobj));
298 return valobj->GetSP();
303 ValueObjectSynthetic::GetChildMemberWithName(ConstString name,
305 UpdateValueIfNeeded();
307 uint32_t index = GetIndexOfChildWithName(name);
309 if (index == UINT32_MAX)
310 return lldb::ValueObjectSP();
312 return GetChildAtIndex(index, can_create);
315 size_t ValueObjectSynthetic::GetIndexOfChildWithName(ConstString name) {
316 UpdateValueIfNeeded();
318 uint32_t found_index = UINT32_MAX;
321 std::lock_guard<std::mutex> guard(m_child_mutex);
322 auto name_to_index = m_name_toindex.find(name.GetCString());
323 did_find = name_to_index != m_name_toindex.end();
325 found_index = name_to_index->second;
328 if (!did_find && m_synth_filter_up != nullptr) {
329 uint32_t index = m_synth_filter_up->GetIndexOfChildWithName(name);
330 if (index == UINT32_MAX)
332 std::lock_guard<std::mutex> guard(m_child_mutex);
333 m_name_toindex[name.GetCString()] = index;
335 } else if (!did_find && m_synth_filter_up == nullptr)
337 else /*if (iter != m_name_toindex.end())*/
341 bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
343 lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
344 return m_parent->GetSP();
347 void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
348 m_value = (source->UpdateValueIfNeeded(), source->GetValue());
349 ExecutionContext exe_ctx(GetExecutionContextRef());
350 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
353 bool ValueObjectSynthetic::CanProvideValue() {
354 if (!UpdateValueIfNeeded())
356 if (m_provides_value == eLazyBoolYes)
358 return m_parent->CanProvideValue();
361 bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
363 return m_parent->SetValueFromCString(value_str, error);
366 void ValueObjectSynthetic::SetFormat(lldb::Format format) {
368 m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
369 m_parent->SetFormat(format);
371 this->ValueObject::SetFormat(format);
372 this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
375 void ValueObjectSynthetic::SetPreferredDisplayLanguage(
376 lldb::LanguageType lang) {
377 this->ValueObject::SetPreferredDisplayLanguage(lang);
379 m_parent->SetPreferredDisplayLanguage(lang);
382 lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
383 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
385 return m_parent->GetPreferredDisplayLanguage();
386 return lldb::eLanguageTypeUnknown;
388 return m_preferred_display_language;
391 bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
393 return m_parent->IsSyntheticChildrenGenerated();
397 void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
399 m_parent->SetSyntheticChildrenGenerated(b);
400 this->ValueObject::SetSyntheticChildrenGenerated(b);
403 bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
405 return m_parent->GetDeclaration(decl);
407 return ValueObject::GetDeclaration(decl);
410 uint64_t ValueObjectSynthetic::GetLanguageFlags() {
412 return m_parent->GetLanguageFlags();
413 return this->ValueObject::GetLanguageFlags();
416 void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
418 m_parent->SetLanguageFlags(flags);
420 this->ValueObject::SetLanguageFlags(flags);