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" // for Value
13 #include "lldb/Core/ValueObject.h"
14 #include "lldb/DataFormatters/TypeSynthetic.h"
15 #include "lldb/Target/ExecutionContext.h" // for ExecutionContext
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet
18 #include "lldb/Utility/SharingPtr.h" // for SharingPtr
19 #include "lldb/Utility/Status.h" // for Status
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 ? false : true);
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 m_synth_filter_ap = (m_synth_sp->GetFrontEnd(*m_parent));
133 if (!m_synth_filter_ap.get())
134 m_synth_filter_ap = llvm::make_unique<DummySyntheticFrontEnd>(*m_parent);
137 bool ValueObjectSynthetic::UpdateValue() {
138 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
140 SetValueIsValid(false);
143 if (!m_parent->UpdateValueIfNeeded(false)) {
144 // our parent could not update.. as we are meaningless without a parent,
146 if (m_parent->GetError().Fail())
147 m_error = m_parent->GetError();
151 // regenerate the synthetic filter if our typename changes
152 // <rdar://problem/12424824>
153 ConstString new_parent_type_name = m_parent->GetTypeName();
154 if (new_parent_type_name != m_parent_type_name) {
156 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
157 "from %s to %s, recomputing synthetic filter",
158 GetName().AsCString(), m_parent_type_name.AsCString(),
159 new_parent_type_name.AsCString());
160 m_parent_type_name = new_parent_type_name;
164 // let our backend do its update
165 if (m_synth_filter_ap->Update() == false) {
167 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
168 "filter said caches are stale - clearing",
169 GetName().AsCString());
170 // filter said that cached values are stale
171 m_children_byindex.Clear();
172 m_name_toindex.Clear();
173 // usually, an object's value can change but this does not alter its
175 // for a synthetic VO that might indeed happen, so we need to tell the upper
177 // that they need to come back to us asking for children
178 m_children_count_valid = false;
179 m_synthetic_children_cache.Clear();
180 m_synthetic_children_count = UINT32_MAX;
181 m_might_have_children = eLazyBoolCalculate;
184 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
185 "filter said caches are still valid",
186 GetName().AsCString());
189 m_provides_value = eLazyBoolCalculate;
191 lldb::ValueObjectSP synth_val(m_synth_filter_ap->GetSyntheticValue());
193 if (synth_val && synth_val->CanProvideValue()) {
195 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
196 "filter said it can provide a value",
197 GetName().AsCString());
199 m_provides_value = eLazyBoolYes;
200 CopyValueData(synth_val.get());
203 log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
204 "filter said it will not provide a value",
205 GetName().AsCString());
207 m_provides_value = eLazyBoolNo;
208 CopyValueData(m_parent);
211 SetValueIsValid(true);
215 lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
217 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
220 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
221 "child at index %zu",
222 GetName().AsCString(), idx);
224 UpdateValueIfNeeded();
227 if (m_children_byindex.GetValueForKey(idx, valobj) == false) {
228 if (can_create && m_synth_filter_ap.get() != nullptr) {
230 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
231 "index %zu not cached and will be created",
232 GetName().AsCString(), idx);
234 lldb::ValueObjectSP synth_guy = m_synth_filter_ap->GetChildAtIndex(idx);
238 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
239 "%zu created as %p (is "
241 GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
243 ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
249 if (synth_guy->IsSyntheticChildrenGenerated())
250 m_synthetic_children_cache.AppendObject(synth_guy);
251 m_children_byindex.SetValueForKey(idx, synth_guy.get());
252 synth_guy->SetPreferredDisplayLanguageIfNeeded(
253 GetPreferredDisplayLanguage());
257 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
258 "index %zu not cached and cannot "
259 "be created (can_create = %s, synth_filter = %p)",
260 GetName().AsCString(), idx, can_create ? "yes" : "no",
261 static_cast<void *>(m_synth_filter_ap.get()));
263 return lldb::ValueObjectSP();
267 log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
268 "index %zu cached as %p",
269 GetName().AsCString(), idx, static_cast<void *>(valobj));
271 return valobj->GetSP();
276 ValueObjectSynthetic::GetChildMemberWithName(const ConstString &name,
278 UpdateValueIfNeeded();
280 uint32_t index = GetIndexOfChildWithName(name);
282 if (index == UINT32_MAX)
283 return lldb::ValueObjectSP();
285 return GetChildAtIndex(index, can_create);
288 size_t ValueObjectSynthetic::GetIndexOfChildWithName(const ConstString &name) {
289 UpdateValueIfNeeded();
291 uint32_t found_index = UINT32_MAX;
292 bool did_find = m_name_toindex.GetValueForKey(name.GetCString(), found_index);
294 if (!did_find && m_synth_filter_ap.get() != nullptr) {
295 uint32_t index = m_synth_filter_ap->GetIndexOfChildWithName(name);
296 if (index == UINT32_MAX)
298 m_name_toindex.SetValueForKey(name.GetCString(), index);
300 } else if (!did_find && m_synth_filter_ap.get() == nullptr)
302 else /*if (iter != m_name_toindex.end())*/
306 bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
308 lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
309 return m_parent->GetSP();
312 void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
313 m_value = (source->UpdateValueIfNeeded(), source->GetValue());
314 ExecutionContext exe_ctx(GetExecutionContextRef());
315 m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
318 bool ValueObjectSynthetic::CanProvideValue() {
319 if (!UpdateValueIfNeeded())
321 if (m_provides_value == eLazyBoolYes)
323 return m_parent->CanProvideValue();
326 bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
328 return m_parent->SetValueFromCString(value_str, error);
331 void ValueObjectSynthetic::SetFormat(lldb::Format format) {
333 m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
334 m_parent->SetFormat(format);
336 this->ValueObject::SetFormat(format);
337 this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
340 void ValueObjectSynthetic::SetPreferredDisplayLanguage(
341 lldb::LanguageType lang) {
342 this->ValueObject::SetPreferredDisplayLanguage(lang);
344 m_parent->SetPreferredDisplayLanguage(lang);
347 lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
348 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
350 return m_parent->GetPreferredDisplayLanguage();
351 return lldb::eLanguageTypeUnknown;
353 return m_preferred_display_language;
356 bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
358 return m_parent->IsSyntheticChildrenGenerated();
362 void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
364 m_parent->SetSyntheticChildrenGenerated(b);
365 this->ValueObject::SetSyntheticChildrenGenerated(b);
368 bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
370 return m_parent->GetDeclaration(decl);
372 return ValueObject::GetDeclaration(decl);
375 uint64_t ValueObjectSynthetic::GetLanguageFlags() {
377 return m_parent->GetLanguageFlags();
378 return this->ValueObject::GetLanguageFlags();
381 void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
383 m_parent->SetLanguageFlags(flags);
385 this->ValueObject::SetLanguageFlags(flags);