Path: blob/main/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp
39587 views
//===-- ValueObjectPrinter.cpp --------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/DataFormatters/ValueObjectPrinter.h"910#include "lldb/Core/ValueObject.h"11#include "lldb/DataFormatters/DataVisualization.h"12#include "lldb/Interpreter/CommandInterpreter.h"13#include "lldb/Target/Language.h"14#include "lldb/Target/Target.h"15#include "lldb/Utility/Stream.h"16#include "llvm/Support/MathExtras.h"17#include <cstdint>1819using namespace lldb;20using namespace lldb_private;2122ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s)23: m_orig_valobj(valobj) {24DumpValueObjectOptions options(valobj);25Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);26}2728ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s,29const DumpValueObjectOptions &options)30: m_orig_valobj(valobj) {31Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);32}3334ValueObjectPrinter::ValueObjectPrinter(35ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options,36const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,37InstancePointersSetSP printed_instance_pointers)38: m_orig_valobj(valobj) {39Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers);40}4142void ValueObjectPrinter::Init(43ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options,44const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,45InstancePointersSetSP printed_instance_pointers) {46m_cached_valobj = nullptr;47m_stream = s;48m_options = options;49m_ptr_depth = ptr_depth;50m_curr_depth = curr_depth;51assert(m_stream && "cannot print to a NULL Stream");52m_should_print = eLazyBoolCalculate;53m_is_nil = eLazyBoolCalculate;54m_is_uninit = eLazyBoolCalculate;55m_is_ptr = eLazyBoolCalculate;56m_is_ref = eLazyBoolCalculate;57m_is_aggregate = eLazyBoolCalculate;58m_is_instance_ptr = eLazyBoolCalculate;59m_summary_formatter = {nullptr, false};60m_value.assign("");61m_summary.assign("");62m_error.assign("");63m_val_summary_ok = false;64m_printed_instance_pointers =65printed_instance_pointers66? printed_instance_pointers67: InstancePointersSetSP(new InstancePointersSet());68SetupMostSpecializedValue();69}7071llvm::Error ValueObjectPrinter::PrintValueObject() {72// If the incoming ValueObject is in an error state, the best we're going to73// get out of it is its type. But if we don't even have that, just print74// the error and exit early.75if (m_orig_valobj.GetError().Fail() &&76!m_orig_valobj.GetCompilerType().IsValid())77return m_orig_valobj.GetError().ToError();7879if (ShouldPrintValueObject()) {80PrintLocationIfNeeded();81m_stream->Indent();8283PrintDecl();84}8586bool value_printed = false;87bool summary_printed = false;8889m_val_summary_ok =90PrintValueAndSummaryIfNeeded(value_printed, summary_printed);9192if (m_val_summary_ok)93return PrintChildrenIfNeeded(value_printed, summary_printed);94m_stream->EOL();9596return llvm::Error::success();97}9899ValueObject &ValueObjectPrinter::GetMostSpecializedValue() {100assert(m_cached_valobj && "ValueObjectPrinter must have a valid ValueObject");101return *m_cached_valobj;102}103104void ValueObjectPrinter::SetupMostSpecializedValue() {105bool update_success = m_orig_valobj.UpdateValueIfNeeded(true);106// If we can't find anything better, we'll fall back on the original107// ValueObject.108m_cached_valobj = &m_orig_valobj;109if (update_success) {110if (m_orig_valobj.IsDynamic()) {111if (m_options.m_use_dynamic == eNoDynamicValues) {112ValueObject *static_value = m_orig_valobj.GetStaticValue().get();113if (static_value)114m_cached_valobj = static_value;115}116} else {117if (m_options.m_use_dynamic != eNoDynamicValues) {118ValueObject *dynamic_value =119m_orig_valobj.GetDynamicValue(m_options.m_use_dynamic).get();120if (dynamic_value)121m_cached_valobj = dynamic_value;122}123}124125if (m_cached_valobj->IsSynthetic()) {126if (!m_options.m_use_synthetic) {127ValueObject *non_synthetic =128m_cached_valobj->GetNonSyntheticValue().get();129if (non_synthetic)130m_cached_valobj = non_synthetic;131}132} else {133if (m_options.m_use_synthetic) {134ValueObject *synthetic = m_cached_valobj->GetSyntheticValue().get();135if (synthetic)136m_cached_valobj = synthetic;137}138}139}140m_compiler_type = m_cached_valobj->GetCompilerType();141m_type_flags = m_compiler_type.GetTypeInfo();142assert(m_cached_valobj &&143"SetupMostSpecialized value must compute a valid ValueObject");144}145146llvm::Expected<std::string> ValueObjectPrinter::GetDescriptionForDisplay() {147ValueObject &valobj = GetMostSpecializedValue();148llvm::Expected<std::string> maybe_str = valobj.GetObjectDescription();149if (maybe_str)150return maybe_str;151152const char *str = nullptr;153if (!str)154str = valobj.GetSummaryAsCString();155if (!str)156str = valobj.GetValueAsCString();157158if (!str)159return maybe_str;160llvm::consumeError(maybe_str.takeError());161return str;162}163164const char *ValueObjectPrinter::GetRootNameForDisplay() {165const char *root_valobj_name =166m_options.m_root_valobj_name.empty()167? GetMostSpecializedValue().GetName().AsCString()168: m_options.m_root_valobj_name.c_str();169return root_valobj_name ? root_valobj_name : "";170}171172bool ValueObjectPrinter::ShouldPrintValueObject() {173if (m_should_print == eLazyBoolCalculate)174m_should_print =175(!m_options.m_flat_output || m_type_flags.Test(eTypeHasValue))176? eLazyBoolYes177: eLazyBoolNo;178return m_should_print == eLazyBoolYes;179}180181bool ValueObjectPrinter::IsNil() {182if (m_is_nil == eLazyBoolCalculate)183m_is_nil =184GetMostSpecializedValue().IsNilReference() ? eLazyBoolYes : eLazyBoolNo;185return m_is_nil == eLazyBoolYes;186}187188bool ValueObjectPrinter::IsUninitialized() {189if (m_is_uninit == eLazyBoolCalculate)190m_is_uninit = GetMostSpecializedValue().IsUninitializedReference()191? eLazyBoolYes192: eLazyBoolNo;193return m_is_uninit == eLazyBoolYes;194}195196bool ValueObjectPrinter::IsPtr() {197if (m_is_ptr == eLazyBoolCalculate)198m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo;199return m_is_ptr == eLazyBoolYes;200}201202bool ValueObjectPrinter::IsRef() {203if (m_is_ref == eLazyBoolCalculate)204m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo;205return m_is_ref == eLazyBoolYes;206}207208bool ValueObjectPrinter::IsAggregate() {209if (m_is_aggregate == eLazyBoolCalculate)210m_is_aggregate =211m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo;212return m_is_aggregate == eLazyBoolYes;213}214215bool ValueObjectPrinter::IsInstancePointer() {216// you need to do this check on the value's clang type217ValueObject &valobj = GetMostSpecializedValue();218if (m_is_instance_ptr == eLazyBoolCalculate)219m_is_instance_ptr = (valobj.GetValue().GetCompilerType().GetTypeInfo() &220eTypeInstanceIsPointer) != 0221? eLazyBoolYes222: eLazyBoolNo;223if ((eLazyBoolYes == m_is_instance_ptr) && valobj.IsBaseClass())224m_is_instance_ptr = eLazyBoolNo;225return m_is_instance_ptr == eLazyBoolYes;226}227228bool ValueObjectPrinter::PrintLocationIfNeeded() {229if (m_options.m_show_location) {230m_stream->Printf("%s: ", GetMostSpecializedValue().GetLocationAsCString());231return true;232}233return false;234}235236void ValueObjectPrinter::PrintDecl() {237bool show_type = true;238// if we are at the root-level and been asked to hide the root's type, then239// hide it240if (m_curr_depth == 0 && m_options.m_hide_root_type)241show_type = false;242else243// otherwise decide according to the usual rules (asked to show types -244// always at the root level)245show_type = m_options.m_show_types ||246(m_curr_depth == 0 && !m_options.m_flat_output);247248StreamString typeName;249// Figure out which ValueObject we're acting on250ValueObject &valobj = GetMostSpecializedValue();251252// always show the type at the root level if it is invalid253if (show_type) {254// Some ValueObjects don't have types (like registers sets). Only print the255// type if there is one to print256ConstString type_name;257if (m_compiler_type.IsValid()) {258type_name = m_options.m_use_type_display_name259? valobj.GetDisplayTypeName()260: valobj.GetQualifiedTypeName();261} else {262// only show an invalid type name if the user explicitly triggered263// show_type264if (m_options.m_show_types)265type_name = ConstString("<invalid type>");266}267268if (type_name) {269std::string type_name_str(type_name.GetCString());270if (m_options.m_hide_pointer_value) {271for (auto iter = type_name_str.find(" *"); iter != std::string::npos;272iter = type_name_str.find(" *")) {273type_name_str.erase(iter, 2);274}275}276typeName << type_name_str.c_str();277}278}279280StreamString varName;281282if (ShouldShowName()) {283if (m_options.m_flat_output)284valobj.GetExpressionPath(varName);285else286varName << GetRootNameForDisplay();287}288289bool decl_printed = false;290if (!m_options.m_decl_printing_helper) {291// if the user didn't give us a custom helper, pick one based upon the292// language, either the one that this printer is bound to, or the preferred293// one for the ValueObject294lldb::LanguageType lang_type =295(m_options.m_varformat_language == lldb::eLanguageTypeUnknown)296? valobj.GetPreferredDisplayLanguage()297: m_options.m_varformat_language;298if (Language *lang_plugin = Language::FindPlugin(lang_type)) {299m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper();300}301}302303if (m_options.m_decl_printing_helper) {304ConstString type_name_cstr(typeName.GetString());305ConstString var_name_cstr(varName.GetString());306307DumpValueObjectOptions decl_print_options = m_options;308// Pass printing helpers an option object that indicates whether the name309// should be shown or hidden.310decl_print_options.SetHideName(!ShouldShowName());311312StreamString dest_stream;313if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr,314decl_print_options, dest_stream)) {315decl_printed = true;316m_stream->PutCString(dest_stream.GetString());317}318}319320// if the helper failed, or there is none, do a default thing321if (!decl_printed) {322if (!typeName.Empty())323m_stream->Printf("(%s) ", typeName.GetData());324if (!varName.Empty())325m_stream->Printf("%s =", varName.GetData());326else if (ShouldShowName())327m_stream->Printf(" =");328}329}330331bool ValueObjectPrinter::CheckScopeIfNeeded() {332if (m_options.m_scope_already_checked)333return true;334return GetMostSpecializedValue().IsInScope();335}336337TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) {338if (!m_summary_formatter.second) {339TypeSummaryImpl *entry =340m_options.m_summary_sp341? m_options.m_summary_sp.get()342: GetMostSpecializedValue().GetSummaryFormat().get();343344if (m_options.m_omit_summary_depth > 0)345entry = nullptr;346m_summary_formatter.first = entry;347m_summary_formatter.second = true;348}349if (m_options.m_omit_summary_depth > 0 && null_if_omitted)350return nullptr;351return m_summary_formatter.first;352}353354static bool IsPointerValue(const CompilerType &type) {355Flags type_flags(type.GetTypeInfo());356if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer))357return type_flags.AllClear(eTypeIsBuiltIn);358return false;359}360361void ValueObjectPrinter::GetValueSummaryError(std::string &value,362std::string &summary,363std::string &error) {364lldb::Format format = m_options.m_format;365ValueObject &valobj = GetMostSpecializedValue();366// if I am printing synthetized elements, apply the format to those elements367// only368if (m_options.m_pointer_as_array)369valobj.GetValueAsCString(lldb::eFormatDefault, value);370else if (format != eFormatDefault && format != valobj.GetFormat())371valobj.GetValueAsCString(format, value);372else {373const char *val_cstr = valobj.GetValueAsCString();374if (val_cstr)375value.assign(val_cstr);376}377const char *err_cstr = valobj.GetError().AsCString();378if (err_cstr)379error.assign(err_cstr);380381if (!ShouldPrintValueObject())382return;383384if (IsNil()) {385lldb::LanguageType lang_type =386(m_options.m_varformat_language == lldb::eLanguageTypeUnknown)387? valobj.GetPreferredDisplayLanguage()388: m_options.m_varformat_language;389if (Language *lang_plugin = Language::FindPlugin(lang_type)) {390summary.assign(lang_plugin->GetNilReferenceSummaryString().str());391} else {392// We treat C as the fallback language rather than as a separate Language393// plugin.394summary.assign("NULL");395}396} else if (IsUninitialized()) {397summary.assign("<uninitialized>");398} else if (m_options.m_omit_summary_depth == 0) {399TypeSummaryImpl *entry = GetSummaryFormatter();400if (entry) {401valobj.GetSummaryAsCString(entry, summary,402m_options.m_varformat_language);403} else {404const char *sum_cstr =405valobj.GetSummaryAsCString(m_options.m_varformat_language);406if (sum_cstr)407summary.assign(sum_cstr);408}409}410}411412bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,413bool &summary_printed) {414bool error_printed = false;415if (ShouldPrintValueObject()) {416if (!CheckScopeIfNeeded())417m_error.assign("out of scope");418if (m_error.empty()) {419GetValueSummaryError(m_value, m_summary, m_error);420}421if (m_error.size()) {422// we need to support scenarios in which it is actually fine for a value423// to have no type but - on the other hand - if we get an error *AND*424// have no type, we try to get out gracefully, since most often that425// combination means "could not resolve a type" and the default failure426// mode is quite ugly427if (!m_compiler_type.IsValid()) {428m_stream->Printf(" <could not resolve type>");429return false;430}431432error_printed = true;433m_stream->Printf(" <%s>\n", m_error.c_str());434} else {435// Make sure we have a value and make sure the summary didn't specify436// that the value should not be printed - and do not print the value if437// this thing is nil (but show the value if the user passes a format438// explicitly)439TypeSummaryImpl *entry = GetSummaryFormatter();440ValueObject &valobj = GetMostSpecializedValue();441const bool has_nil_or_uninitialized_summary =442(IsNil() || IsUninitialized()) && !m_summary.empty();443if (!has_nil_or_uninitialized_summary && !m_value.empty() &&444(entry == nullptr ||445(entry->DoesPrintValue(&valobj) ||446m_options.m_format != eFormatDefault) ||447m_summary.empty()) &&448!m_options.m_hide_value) {449if (m_options.m_hide_pointer_value &&450IsPointerValue(valobj.GetCompilerType())) {451} else {452if (ShouldShowName())453m_stream->PutChar(' ');454m_stream->PutCString(m_value);455value_printed = true;456}457}458459if (m_summary.size()) {460if (ShouldShowName() || value_printed)461m_stream->PutChar(' ');462m_stream->PutCString(m_summary);463summary_printed = true;464}465}466}467return !error_printed;468}469470llvm::Error471ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,472bool summary_printed) {473if (ShouldPrintValueObject()) {474// let's avoid the overly verbose no description error for a nil thing475if (m_options.m_use_objc && !IsNil() && !IsUninitialized() &&476(!m_options.m_pointer_as_array)) {477if (!m_options.m_hide_value || ShouldShowName())478*m_stream << ' ';479llvm::Expected<std::string> object_desc =480(value_printed || summary_printed)481? GetMostSpecializedValue().GetObjectDescription()482: GetDescriptionForDisplay();483if (!object_desc) {484// If no value or summary was printed, surface the error.485if (!value_printed && !summary_printed)486return object_desc.takeError();487// Otherwise gently nudge the user that they should have used488// `p` instead of `po`. Unfortunately we cannot be more direct489// about this, because we don't actually know what the user did.490*m_stream << "warning: no object description available\n";491llvm::consumeError(object_desc.takeError());492} else {493*m_stream << *object_desc;494// If the description already ends with a \n don't add another one.495if (object_desc->empty() || object_desc->back() != '\n')496*m_stream << '\n';497}498return llvm::Error::success();499}500}501return llvm::Error::success();502}503504bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {505switch (m_mode) {506case Mode::Always:507case Mode::Default:508return m_count > 0;509case Mode::Never:510return false;511}512return false;513}514515bool ValueObjectPrinter::ShouldPrintChildren(516DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {517const bool is_ref = IsRef();518const bool is_ptr = IsPtr();519const bool is_uninit = IsUninitialized();520521if (is_uninit)522return false;523524// If we have reached the maximum depth we shouldn't print any more children.525if (HasReachedMaximumDepth())526return false;527528// if the user has specified an element count, always print children as it is529// explicit user demand being honored530if (m_options.m_pointer_as_array)531return true;532533if (m_options.m_use_objc)534return false;535536bool print_children = true;537ValueObject &valobj = GetMostSpecializedValue();538if (TypeSummaryImpl *type_summary = GetSummaryFormatter())539print_children = type_summary->DoesPrintChildren(&valobj);540541// We will show children for all concrete types. We won't show pointer542// contents unless a pointer depth has been specified. We won't reference543// contents unless the reference is the root object (depth of zero).544545// Use a new temporary pointer depth in case we override the current546// pointer depth below...547548if (is_ptr || is_ref) {549// We have a pointer or reference whose value is an address. Make sure550// that address is not NULL551AddressType ptr_address_type;552if (valobj.GetPointerValue(&ptr_address_type) == 0)553return false;554555const bool is_root_level = m_curr_depth == 0;556557if (is_ref && is_root_level && print_children) {558// If this is the root object (depth is zero) that we are showing and559// it is a reference, and no pointer depth has been supplied print out560// what it references. Don't do this at deeper depths otherwise we can561// end up with infinite recursion...562return true;563}564565return curr_ptr_depth.CanAllowExpansion();566}567568return print_children || m_summary.empty();569}570571bool ValueObjectPrinter::ShouldExpandEmptyAggregates() {572TypeSummaryImpl *entry = GetSummaryFormatter();573574if (!entry)575return true;576577return entry->DoesPrintEmptyAggregates();578}579580ValueObject &ValueObjectPrinter::GetValueObjectForChildrenGeneration() {581return GetMostSpecializedValue();582}583584void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed,585bool summary_printed) {586if (m_options.m_flat_output) {587if (ShouldPrintValueObject())588m_stream->EOL();589} else {590if (ShouldPrintValueObject()) {591if (IsRef()) {592m_stream->PutCString(": ");593} else if (value_printed || summary_printed || ShouldShowName()) {594m_stream->PutChar(' ');595}596m_stream->PutCString("{\n");597}598m_stream->IndentMore();599}600}601602void ValueObjectPrinter::PrintChild(603ValueObjectSP child_sp,604const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {605const uint32_t consumed_summary_depth = m_options.m_pointer_as_array ? 0 : 1;606const bool does_consume_ptr_depth =607((IsPtr() && !m_options.m_pointer_as_array) || IsRef());608609DumpValueObjectOptions child_options(m_options);610child_options.SetFormat(m_options.m_format)611.SetSummary()612.SetRootValueObjectName();613child_options.SetScopeChecked(true)614.SetHideName(m_options.m_hide_name)615.SetHideValue(m_options.m_hide_value)616.SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1617? child_options.m_omit_summary_depth -618consumed_summary_depth619: 0)620.SetElementCount(0);621622if (child_sp.get()) {623auto ptr_depth = curr_ptr_depth;624if (does_consume_ptr_depth)625ptr_depth = curr_ptr_depth.Decremented();626627ValueObjectPrinter child_printer(*(child_sp.get()), m_stream, child_options,628ptr_depth, m_curr_depth + 1,629m_printed_instance_pointers);630llvm::Error error = child_printer.PrintValueObject();631if (error) {632if (m_stream)633*m_stream << "error: " << toString(std::move(error));634else635llvm::consumeError(std::move(error));636}637}638}639640llvm::Expected<uint32_t>641ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) {642ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();643644if (m_options.m_pointer_as_array)645return m_options.m_pointer_as_array.m_element_count;646647const uint32_t max_num_children =648m_options.m_ignore_cap ? UINT32_MAX649: GetMostSpecializedValue()650.GetTargetSP()651->GetMaximumNumberOfChildrenToDisplay();652// Ask for one more child than the maximum to see if we should print "...".653auto num_children_or_err = synth_valobj.GetNumChildren(654llvm::SaturatingAdd(max_num_children, uint32_t(1)));655if (!num_children_or_err)656return num_children_or_err;657if (*num_children_or_err > max_num_children) {658print_dotdotdot = true;659return max_num_children;660}661return num_children_or_err;662}663664void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) {665if (!m_options.m_flat_output) {666if (print_dotdotdot) {667GetMostSpecializedValue()668.GetTargetSP()669->GetDebugger()670.GetCommandInterpreter()671.ChildrenTruncated();672m_stream->Indent("...\n");673}674m_stream->IndentLess();675m_stream->Indent("}\n");676}677}678679bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed,680bool summary_printed) {681ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();682683if (!IsAggregate())684return false;685686if (!m_options.m_reveal_empty_aggregates) {687if (value_printed || summary_printed)688return false;689}690691if (synth_valobj.MightHaveChildren())692return true;693694if (m_val_summary_ok)695return false;696697return true;698}699700static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride,701size_t logical) {702return base + logical * stride;703}704705ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject &synth_valobj,706size_t idx) {707if (m_options.m_pointer_as_array) {708// if generating pointer-as-array children, use GetSyntheticArrayMember709return synth_valobj.GetSyntheticArrayMember(710PhysicalIndexForLogicalIndex(711m_options.m_pointer_as_array.m_base_element,712m_options.m_pointer_as_array.m_stride, idx),713true);714} else {715// otherwise, do the usual thing716return synth_valobj.GetChildAtIndex(idx);717}718}719720void ValueObjectPrinter::PrintChildren(721bool value_printed, bool summary_printed,722const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {723ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();724725bool print_dotdotdot = false;726auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);727if (!num_children_or_err) {728*m_stream << " <" << llvm::toString(num_children_or_err.takeError()) << '>';729return;730}731uint32_t num_children = *num_children_or_err;732if (num_children) {733bool any_children_printed = false;734735for (size_t idx = 0; idx < num_children; ++idx) {736if (ValueObjectSP child_sp = GenerateChild(synth_valobj, idx)) {737if (m_options.m_child_printing_decider &&738!m_options.m_child_printing_decider(child_sp->GetName()))739continue;740if (!any_children_printed) {741PrintChildrenPreamble(value_printed, summary_printed);742any_children_printed = true;743}744PrintChild(child_sp, curr_ptr_depth);745}746}747748if (any_children_printed)749PrintChildrenPostamble(print_dotdotdot);750else {751if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {752if (ShouldPrintValueObject())753m_stream->PutCString(" {}\n");754else755m_stream->EOL();756} else757m_stream->EOL();758}759} else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {760// Aggregate, no children...761if (ShouldPrintValueObject()) {762// if it has a synthetic value, then don't print {}, the synthetic763// children are probably only being used to vend a value764if (GetMostSpecializedValue().DoesProvideSyntheticValue() ||765!ShouldExpandEmptyAggregates())766m_stream->PutCString("\n");767else768m_stream->PutCString(" {}\n");769}770} else {771if (ShouldPrintValueObject())772m_stream->EOL();773}774}775776bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {777ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();778779bool print_dotdotdot = false;780auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);781if (!num_children_or_err) {782*m_stream << '<' << llvm::toString(num_children_or_err.takeError()) << '>';783return true;784}785uint32_t num_children = *num_children_or_err;786787if (num_children) {788m_stream->PutChar('(');789790bool did_print_children = false;791for (uint32_t idx = 0; idx < num_children; ++idx) {792lldb::ValueObjectSP child_sp(synth_valobj.GetChildAtIndex(idx));793if (child_sp)794child_sp = child_sp->GetQualifiedRepresentationIfAvailable(795m_options.m_use_dynamic, m_options.m_use_synthetic);796if (child_sp) {797if (m_options.m_child_printing_decider &&798!m_options.m_child_printing_decider(child_sp->GetName()))799continue;800if (idx && did_print_children)801m_stream->PutCString(", ");802did_print_children = true;803if (!hide_names) {804const char *name = child_sp.get()->GetName().AsCString();805if (name && *name) {806m_stream->PutCString(name);807m_stream->PutCString(" = ");808}809}810child_sp->DumpPrintableRepresentation(811*m_stream, ValueObject::eValueObjectRepresentationStyleSummary,812m_options.m_format,813ValueObject::PrintableRepresentationSpecialCases::eDisable);814}815}816817if (print_dotdotdot)818m_stream->PutCString(", ...)");819else820m_stream->PutChar(')');821}822return true;823}824825llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,826bool summary_printed) {827auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed);828if (error)829return error;830831ValueObject &valobj = GetMostSpecializedValue();832833DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth;834const bool print_children = ShouldPrintChildren(curr_ptr_depth);835const bool print_oneline =836(curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types ||837!m_options.m_allow_oneliner_mode || m_options.m_flat_output ||838(m_options.m_pointer_as_array) || m_options.m_show_location)839? false840: DataVisualization::ShouldPrintAsOneLiner(valobj);841if (print_children && IsInstancePointer()) {842uint64_t instance_ptr_value = valobj.GetValueAsUnsigned(0);843if (m_printed_instance_pointers->count(instance_ptr_value)) {844// We already printed this instance-is-pointer thing, so don't expand it.845m_stream->PutCString(" {...}\n");846return llvm::Error::success();847} else {848// Remember this guy for future reference.849m_printed_instance_pointers->emplace(instance_ptr_value);850}851}852853if (print_children) {854if (print_oneline) {855m_stream->PutChar(' ');856PrintChildrenOneLiner(false);857m_stream->EOL();858} else859PrintChildren(value_printed, summary_printed, curr_ptr_depth);860} else if (HasReachedMaximumDepth() && IsAggregate() &&861ShouldPrintValueObject()) {862m_stream->PutCString("{...}\n");863// The maximum child depth has been reached. If `m_max_depth` is the default864// (i.e. the user has _not_ customized it), then lldb presents a warning to865// the user. The warning tells the user that the limit has been reached, but866// more importantly tells them how to expand the limit if desired.867if (m_options.m_max_depth_is_default)868valobj.GetTargetSP()869->GetDebugger()870.GetCommandInterpreter()871.SetReachedMaximumDepth();872} else873m_stream->EOL();874return llvm::Error::success();875}876877bool ValueObjectPrinter::HasReachedMaximumDepth() {878return m_curr_depth >= m_options.m_max_depth;879}880881bool ValueObjectPrinter::ShouldShowName() const {882if (m_curr_depth == 0)883return !m_options.m_hide_root_name && !m_options.m_hide_name;884return !m_options.m_hide_name;885}886887888