blob: 044387a4ae12214a3b798b2272878538b8f04b6b [file] [log] [blame]
//===-- ValueObjectSyntheticFilter.cpp --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/ValueObjectSyntheticFilter.h"
#include "lldb/Core/Value.h" // for Value
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Target/ExecutionContext.h" // for ExecutionContext
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet
#include "lldb/Utility/SharingPtr.h" // for SharingPtr
#include "lldb/Utility/Status.h" // for Status
#include "llvm/ADT/STLExtras.h"
namespace lldb_private {
class Declaration;
}
using namespace lldb_private;
class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
DummySyntheticFrontEnd(ValueObject &backend)
: SyntheticChildrenFrontEnd(backend) {}
size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); }
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
return m_backend.GetChildAtIndex(idx, true);
}
size_t GetIndexOfChildWithName(const ConstString &name) override {
return m_backend.GetIndexOfChildWithName(name);
}
bool MightHaveChildren() override { return true; }
bool Update() override { return false; }
};
ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
lldb::SyntheticChildrenSP filter)
: ValueObject(parent), m_synth_sp(filter), m_children_byindex(),
m_name_toindex(), m_synthetic_children_count(UINT32_MAX),
m_synthetic_children_cache(), m_parent_type_name(parent.GetTypeName()),
m_might_have_children(eLazyBoolCalculate),
m_provides_value(eLazyBoolCalculate) {
SetName(parent.GetName());
CopyValueData(m_parent);
CreateSynthFilter();
}
ValueObjectSynthetic::~ValueObjectSynthetic() = default;
CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {
return m_parent->GetCompilerType();
}
ConstString ValueObjectSynthetic::GetTypeName() {
return m_parent->GetTypeName();
}
ConstString ValueObjectSynthetic::GetQualifiedTypeName() {
return m_parent->GetQualifiedTypeName();
}
ConstString ValueObjectSynthetic::GetDisplayTypeName() {
if (ConstString synth_name = m_synth_filter_ap->GetSyntheticTypeName())
return synth_name;
return m_parent->GetDisplayTypeName();
}
size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
UpdateValueIfNeeded();
if (m_synthetic_children_count < UINT32_MAX)
return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
if (max < UINT32_MAX) {
size_t num_children = m_synth_filter_ap->CalculateNumChildren(max);
if (log)
log->Printf("[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
"%s and type %s, the filter returned %zu child values",
GetName().AsCString(), GetTypeName().AsCString(),
num_children);
return num_children;
} else {
size_t num_children = (m_synthetic_children_count =
m_synth_filter_ap->CalculateNumChildren(max));
if (log)
log->Printf("[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
"%s and type %s, the filter returned %zu child values",
GetName().AsCString(), GetTypeName().AsCString(),
num_children);
return num_children;
}
}
lldb::ValueObjectSP
ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
if (!m_parent)
return lldb::ValueObjectSP();
if (IsDynamic() && GetDynamicValueType() == valueType)
return GetSP();
return m_parent->GetDynamicValue(valueType);
}
bool ValueObjectSynthetic::MightHaveChildren() {
if (m_might_have_children == eLazyBoolCalculate)
m_might_have_children =
(m_synth_filter_ap->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
return (m_might_have_children == eLazyBoolNo ? false : true);
}
uint64_t ValueObjectSynthetic::GetByteSize() { return m_parent->GetByteSize(); }
lldb::ValueType ValueObjectSynthetic::GetValueType() const {
return m_parent->GetValueType();
}
void ValueObjectSynthetic::CreateSynthFilter() {
ValueObject *valobj_for_frontend = m_parent;
if (m_synth_sp->WantsDereference())
{
CompilerType type = m_parent->GetCompilerType();
if (type.IsValid() && type.IsPointerOrReferenceType())
{
Status error;
lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
if (error.Success())
valobj_for_frontend = deref_sp.get();
}
}
m_synth_filter_ap = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
if (!m_synth_filter_ap.get())
m_synth_filter_ap = llvm::make_unique<DummySyntheticFrontEnd>(*m_parent);
}
bool ValueObjectSynthetic::UpdateValue() {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
SetValueIsValid(false);
m_error.Clear();
if (!m_parent->UpdateValueIfNeeded(false)) {
// our parent could not update.. as we are meaningless without a parent,
// just stop
if (m_parent->GetError().Fail())
m_error = m_parent->GetError();
return false;
}
// regenerate the synthetic filter if our typename changes
// <rdar://problem/12424824>
ConstString new_parent_type_name = m_parent->GetTypeName();
if (new_parent_type_name != m_parent_type_name) {
if (log)
log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
"from %s to %s, recomputing synthetic filter",
GetName().AsCString(), m_parent_type_name.AsCString(),
new_parent_type_name.AsCString());
m_parent_type_name = new_parent_type_name;
CreateSynthFilter();
}
// let our backend do its update
if (m_synth_filter_ap->Update() == false) {
if (log)
log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
"filter said caches are stale - clearing",
GetName().AsCString());
// filter said that cached values are stale
m_children_byindex.Clear();
m_name_toindex.Clear();
// usually, an object's value can change but this does not alter its
// children count for a synthetic VO that might indeed happen, so we need
// to tell the upper echelons that they need to come back to us asking for
// children
m_children_count_valid = false;
m_synthetic_children_cache.Clear();
m_synthetic_children_count = UINT32_MAX;
m_might_have_children = eLazyBoolCalculate;
} else {
if (log)
log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
"filter said caches are still valid",
GetName().AsCString());
}
m_provides_value = eLazyBoolCalculate;
lldb::ValueObjectSP synth_val(m_synth_filter_ap->GetSyntheticValue());
if (synth_val && synth_val->CanProvideValue()) {
if (log)
log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
"filter said it can provide a value",
GetName().AsCString());
m_provides_value = eLazyBoolYes;
CopyValueData(synth_val.get());
} else {
if (log)
log->Printf("[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
"filter said it will not provide a value",
GetName().AsCString());
m_provides_value = eLazyBoolNo;
CopyValueData(m_parent);
}
SetValueIsValid(true);
return true;
}
lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
bool can_create) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS);
if (log)
log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
"child at index %zu",
GetName().AsCString(), idx);
UpdateValueIfNeeded();
ValueObject *valobj;
if (m_children_byindex.GetValueForKey(idx, valobj) == false) {
if (can_create && m_synth_filter_ap.get() != nullptr) {
if (log)
log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
"index %zu not cached and will be created",
GetName().AsCString(), idx);
lldb::ValueObjectSP synth_guy = m_synth_filter_ap->GetChildAtIndex(idx);
if (log)
log->Printf(
"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
"%zu created as %p (is "
"synthetic: %s)",
GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
synth_guy.get()
? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
: "no");
if (!synth_guy)
return synth_guy;
if (synth_guy->IsSyntheticChildrenGenerated())
m_synthetic_children_cache.AppendObject(synth_guy);
m_children_byindex.SetValueForKey(idx, synth_guy.get());
synth_guy->SetPreferredDisplayLanguageIfNeeded(
GetPreferredDisplayLanguage());
return synth_guy;
} else {
if (log)
log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
"index %zu not cached and cannot "
"be created (can_create = %s, synth_filter = %p)",
GetName().AsCString(), idx, can_create ? "yes" : "no",
static_cast<void *>(m_synth_filter_ap.get()));
return lldb::ValueObjectSP();
}
} else {
if (log)
log->Printf("[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
"index %zu cached as %p",
GetName().AsCString(), idx, static_cast<void *>(valobj));
return valobj->GetSP();
}
}
lldb::ValueObjectSP
ValueObjectSynthetic::GetChildMemberWithName(const ConstString &name,
bool can_create) {
UpdateValueIfNeeded();
uint32_t index = GetIndexOfChildWithName(name);
if (index == UINT32_MAX)
return lldb::ValueObjectSP();
return GetChildAtIndex(index, can_create);
}
size_t ValueObjectSynthetic::GetIndexOfChildWithName(const ConstString &name) {
UpdateValueIfNeeded();
uint32_t found_index = UINT32_MAX;
bool did_find = m_name_toindex.GetValueForKey(name.GetCString(), found_index);
if (!did_find && m_synth_filter_ap.get() != nullptr) {
uint32_t index = m_synth_filter_ap->GetIndexOfChildWithName(name);
if (index == UINT32_MAX)
return index;
m_name_toindex.SetValueForKey(name.GetCString(), index);
return index;
} else if (!did_find && m_synth_filter_ap.get() == nullptr)
return UINT32_MAX;
else /*if (iter != m_name_toindex.end())*/
return found_index;
}
bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
return m_parent->GetSP();
}
void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
m_value = (source->UpdateValueIfNeeded(), source->GetValue());
ExecutionContext exe_ctx(GetExecutionContextRef());
m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
}
bool ValueObjectSynthetic::CanProvideValue() {
if (!UpdateValueIfNeeded())
return false;
if (m_provides_value == eLazyBoolYes)
return true;
return m_parent->CanProvideValue();
}
bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
Status &error) {
return m_parent->SetValueFromCString(value_str, error);
}
void ValueObjectSynthetic::SetFormat(lldb::Format format) {
if (m_parent) {
m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
m_parent->SetFormat(format);
}
this->ValueObject::SetFormat(format);
this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
}
void ValueObjectSynthetic::SetPreferredDisplayLanguage(
lldb::LanguageType lang) {
this->ValueObject::SetPreferredDisplayLanguage(lang);
if (m_parent)
m_parent->SetPreferredDisplayLanguage(lang);
}
lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
if (m_parent)
return m_parent->GetPreferredDisplayLanguage();
return lldb::eLanguageTypeUnknown;
} else
return m_preferred_display_language;
}
bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
if (m_parent)
return m_parent->IsSyntheticChildrenGenerated();
return false;
}
void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
if (m_parent)
m_parent->SetSyntheticChildrenGenerated(b);
this->ValueObject::SetSyntheticChildrenGenerated(b);
}
bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
if (m_parent)
return m_parent->GetDeclaration(decl);
return ValueObject::GetDeclaration(decl);
}
uint64_t ValueObjectSynthetic::GetLanguageFlags() {
if (m_parent)
return m_parent->GetLanguageFlags();
return this->ValueObject::GetLanguageFlags();
}
void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
if (m_parent)
m_parent->SetLanguageFlags(flags);
else
this->ValueObject::SetLanguageFlags(flags);
}