1 //===-- ValueObjectSyntheticFilter.cpp --------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Core/ValueObjectSyntheticFilter.h"
12 #include "lldb/Core/Value.h"
13 #include "lldb/Core/ValueObject.h"
14 #include "lldb/DataFormatters/TypeSynthetic.h"
15 #include "lldb/Target/ExecutionContext.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/Logging.h"
18 #include "lldb/Utility/SharingPtr.h"
19 #include "lldb/Utility/Status.h"
21 #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 size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); }
36 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
37 return m_backend.GetChildAtIndex(idx, true);
40 size_t GetIndexOfChildWithName(const ConstString &name) override {
41 return m_backend.GetIndexOfChildWithName(name);
44 bool MightHaveChildren() override { return true; }
46 bool Update() override { return false; }
49 ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
50 lldb::SyntheticChildrenSP filter)
51 : ValueObject(parent), m_synth_sp(filter), m_children_byindex(),
52 m_name_toindex(), m_synthetic_children_count(UINT32_MAX),
53 m_synthetic_children_cache(), 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_ap->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_ap->CalculateNumChildren(max);
92 log->Printf("[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
93 "%s and type %s, the filter returned %zu child values",
94 GetName().AsCString(), GetTypeName().AsCString(),
98 size_t num_children = (m_synthetic_children_count =
99 m_synth_filter_ap->CalculateNumChildren(max));
101 log->Printf("[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
102 "%s and type %s, the filter returned %zu child values",
103 GetName().AsCString(), GetTypeName().AsCString(),
110 ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
112 return lldb::ValueObjectSP();
113 if (IsDynamic() && GetDynamicValueType() == valueType)
115 return m_parent->GetDynamicValue(valueType);
118 bool ValueObjectSynthetic::MightHaveChildren() {
119 if (m_might_have_children == eLazyBoolCalculate)
120 m_might_have_children =
121 (m_synth_filter_ap->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
122 return (m_might_have_children != eLazyBoolNo);
125 uint64_t ValueObjectSynthetic::GetByteSize() { return m_parent->GetByteSize(); }
127 lldb::ValueType ValueObjectSynthetic::GetValueType() const {
128 return m_parent->GetValueType();
131 void ValueObjectSynthetic::CreateSynthFilter() {
132 ValueObject *valobj_for_frontend = m_parent;
133 if (m_synth_sp->WantsDereference())
135 CompilerType type = m_parent->GetCompilerType();
136 if (type.IsValid() && type.IsPointerOrReferenceType())
139 lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
141 valobj_for_frontend = deref_sp.get();
144 m_synth_filter_ap = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
145 if (!m_synth_filter_ap.get())
146 m_synth_filter_ap = llvm::make_unique<DummySyntheticFrontEnd>(*m_parent);
149 bool ValueObjectSynthetic::UpdateValue() {
150 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
152 SetValueIsValid(false);
155 if (!m_parent->UpdateValueIfNeeded(false)) {
156 // our parent could not update.. as we are meaningless without a parent,
158 if (m_parent->GetError().Fail())
159 m_error = m_parent->GetError();
163 // regenerate the synthetic filter if our typename changes
164 // <rdar://problem/12424824>
165 ConstString new_parent_type_name = m_parent->GetTypeName();
166 if (new_parent_type_name != m_parent_type_name) {
168 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
169 "from %s to %s, recomputing synthetic filter",
170 GetName().AsCString(), m_parent_type_name.AsCString(),
171 new_parent_type_name.AsCString());
172 m_parent_type_name = new_parent_type_name;
176 // let our backend do its update
177 if (!m_synth_filter_ap->Update()) {
179 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
180 "filter said caches are stale - clearing",
181 GetName().AsCString());
182 // filter said that cached values are stale
183 m_children_byindex.Clear();
184 m_name_toindex.Clear();
185 // usually, an object's value can change but this does not alter its
186 // children count for a synthetic VO that might indeed happen, so we need
187 // to tell the upper echelons that they need to come back to us asking for
189 m_children_count_valid = false;
190 m_synthetic_children_cache.Clear();
191 m_synthetic_children_count = UINT32_MAX;
192 m_might_have_children = eLazyBoolCalculate;
195 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
196 "filter said caches are still valid",
197 GetName().AsCString());
200 m_provides_value = eLazyBoolCalculate;
202 lldb::ValueObjectSP synth_val(m_synth_filter_ap->GetSyntheticValue());
204 if (synth_val && synth_val->CanProvideValue()) {
206 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
207 "filter said it can provide a value",
208 GetName().AsCString());
210 m_provides_value = eLazyBoolYes;
211 CopyValueData(synth_val.get());
214 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
215 "filter said it will not provide a value",
216 GetName().AsCString());
218 m_provides_value = eLazyBoolNo;
219 CopyValueData(m_parent);
222 SetValueIsValid(true);
226 lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
228 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
231 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
232 "child at index %zu",
233 GetName().AsCString(), idx);
235 UpdateValueIfNeeded();
238 if (!m_children_byindex.GetValueForKey(idx, valobj)) {
239 if (can_create && m_synth_filter_ap.get() != nullptr) {
241 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
242 "index %zu not cached and will be created",
243 GetName().AsCString(), idx);
245 lldb::ValueObjectSP synth_guy = m_synth_filter_ap->GetChildAtIndex(idx);
249 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
250 "%zu created as %p (is "
252 GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
254 ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
260 if (synth_guy->IsSyntheticChildrenGenerated())
261 m_synthetic_children_cache.AppendObject(synth_guy);
262 m_children_byindex.SetValueForKey(idx, synth_guy.get());
263 synth_guy->SetPreferredDisplayLanguageIfNeeded(
264 GetPreferredDisplayLanguage());
268 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
269 "index %zu not cached and cannot "
270 "be created (can_create = %s, synth_filter = %p)",
271 GetName().AsCString(), idx, can_create ? "yes" : "no",
272 static_cast<void *>(m_synth_filter_ap.get()));
274 return lldb::ValueObjectSP();
278 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
279 "index %zu cached as %p",
280 GetName().AsCString(), idx, static_cast<void *>(valobj));
282 return valobj->GetSP();
287 ValueObjectSynthetic::GetChildMemberWithName(const ConstString &name,
289 UpdateValueIfNeeded();
291 uint32_t index = GetIndexOfChildWithName(name);
293 if (index == UINT32_MAX)
294 return lldb::ValueObjectSP();
296 return GetChildAtIndex(index, can_create);
299 size_t ValueObjectSynthetic::GetIndexOfChildWithName(const ConstString &name) {
300 UpdateValueIfNeeded();
302 uint32_t found_index = UINT32_MAX;
303 bool did_find = m_name_toindex.GetValueForKey(name.GetCString(), found_index);
305 if (!did_find && m_synth_filter_ap.get() != nullptr) {
306 uint32_t index = m_synth_filter_ap->GetIndexOfChildWithName(name);
307 if (index == UINT32_MAX)
309 m_name_toindex.SetValueForKey(name.GetCString(), index);
311 } else if (!did_find && m_synth_filter_ap.get() == nullptr)
313 else /*if (iter != m_name_toindex.end())*/
317 bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
319 lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
320 return m_parent->GetSP();
323 void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
324 m_value = (source->UpdateValueIfNeeded(), source->GetValue());
325 ExecutionContext exe_ctx(GetExecutionContextRef());
326 m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
329 bool ValueObjectSynthetic::CanProvideValue() {
330 if (!UpdateValueIfNeeded())
332 if (m_provides_value == eLazyBoolYes)
334 return m_parent->CanProvideValue();
337 bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
339 return m_parent->SetValueFromCString(value_str, error);
342 void ValueObjectSynthetic::SetFormat(lldb::Format format) {
344 m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
345 m_parent->SetFormat(format);
347 this->ValueObject::SetFormat(format);
348 this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
351 void ValueObjectSynthetic::SetPreferredDisplayLanguage(
352 lldb::LanguageType lang) {
353 this->ValueObject::SetPreferredDisplayLanguage(lang);
355 m_parent->SetPreferredDisplayLanguage(lang);
358 lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
359 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
361 return m_parent->GetPreferredDisplayLanguage();
362 return lldb::eLanguageTypeUnknown;
364 return m_preferred_display_language;
367 bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
369 return m_parent->IsSyntheticChildrenGenerated();
373 void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
375 m_parent->SetSyntheticChildrenGenerated(b);
376 this->ValueObject::SetSyntheticChildrenGenerated(b);
379 bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
381 return m_parent->GetDeclaration(decl);
383 return ValueObject::GetDeclaration(decl);
386 uint64_t ValueObjectSynthetic::GetLanguageFlags() {
388 return m_parent->GetLanguageFlags();
389 return this->ValueObject::GetLanguageFlags();
392 void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
394 m_parent->SetLanguageFlags(flags);
396 this->ValueObject::SetLanguageFlags(flags);