1 //===-- ValueObjectPrinter.cpp --------------------------------------------===//
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/DataFormatters/ValueObjectPrinter.h"
11 #include "lldb/Core/ValueObject.h"
12 #include "lldb/DataFormatters/DataVisualization.h"
13 #include "lldb/Interpreter/CommandInterpreter.h"
14 #include "lldb/Target/Language.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Utility/Stream.h"
19 using namespace lldb_private
;
21 ValueObjectPrinter::ValueObjectPrinter(ValueObject
*valobj
, Stream
*s
) {
23 DumpValueObjectOptions
options(*valobj
);
24 Init(valobj
, s
, options
, m_options
.m_max_ptr_depth
, 0, nullptr);
26 DumpValueObjectOptions options
;
27 Init(valobj
, s
, options
, m_options
.m_max_ptr_depth
, 0, nullptr);
31 ValueObjectPrinter::ValueObjectPrinter(ValueObject
*valobj
, Stream
*s
,
32 const DumpValueObjectOptions
&options
) {
33 Init(valobj
, s
, options
, m_options
.m_max_ptr_depth
, 0, nullptr);
36 ValueObjectPrinter::ValueObjectPrinter(
37 ValueObject
*valobj
, Stream
*s
, const DumpValueObjectOptions
&options
,
38 const DumpValueObjectOptions::PointerDepth
&ptr_depth
, uint32_t curr_depth
,
39 InstancePointersSetSP printed_instance_pointers
) {
40 Init(valobj
, s
, options
, ptr_depth
, curr_depth
, printed_instance_pointers
);
43 void ValueObjectPrinter::Init(
44 ValueObject
*valobj
, Stream
*s
, const DumpValueObjectOptions
&options
,
45 const DumpValueObjectOptions::PointerDepth
&ptr_depth
, uint32_t curr_depth
,
46 InstancePointersSetSP printed_instance_pointers
) {
47 m_orig_valobj
= valobj
;
51 m_ptr_depth
= ptr_depth
;
52 m_curr_depth
= curr_depth
;
53 assert(m_orig_valobj
&& "cannot print a NULL ValueObject");
54 assert(m_stream
&& "cannot print to a NULL Stream");
55 m_should_print
= eLazyBoolCalculate
;
56 m_is_nil
= eLazyBoolCalculate
;
57 m_is_uninit
= eLazyBoolCalculate
;
58 m_is_ptr
= eLazyBoolCalculate
;
59 m_is_ref
= eLazyBoolCalculate
;
60 m_is_aggregate
= eLazyBoolCalculate
;
61 m_is_instance_ptr
= eLazyBoolCalculate
;
62 m_summary_formatter
= {nullptr, false};
66 m_val_summary_ok
= false;
67 m_printed_instance_pointers
=
68 printed_instance_pointers
69 ? printed_instance_pointers
70 : InstancePointersSetSP(new InstancePointersSet());
73 bool ValueObjectPrinter::PrintValueObject() {
77 // If the incoming ValueObject is in an error state, the best we're going to
78 // get out of it is its type. But if we don't even have that, just print
79 // the error and exit early.
80 if (m_orig_valobj
->GetError().Fail()
81 && !m_orig_valobj
->GetCompilerType().IsValid()) {
82 m_stream
->Printf("Error: '%s'", m_orig_valobj
->GetError().AsCString());
86 if (!GetMostSpecializedValue() || m_valobj
== nullptr)
89 if (ShouldPrintValueObject()) {
90 PrintLocationIfNeeded();
96 bool value_printed
= false;
97 bool summary_printed
= false;
100 PrintValueAndSummaryIfNeeded(value_printed
, summary_printed
);
102 if (m_val_summary_ok
)
103 PrintChildrenIfNeeded(value_printed
, summary_printed
);
110 bool ValueObjectPrinter::GetMostSpecializedValue() {
113 bool update_success
= m_orig_valobj
->UpdateValueIfNeeded(true);
114 if (!update_success
) {
115 m_valobj
= m_orig_valobj
;
117 if (m_orig_valobj
->IsDynamic()) {
118 if (m_options
.m_use_dynamic
== eNoDynamicValues
) {
119 ValueObject
*static_value
= m_orig_valobj
->GetStaticValue().get();
121 m_valobj
= static_value
;
123 m_valobj
= m_orig_valobj
;
125 m_valobj
= m_orig_valobj
;
127 if (m_options
.m_use_dynamic
!= eNoDynamicValues
) {
128 ValueObject
*dynamic_value
=
129 m_orig_valobj
->GetDynamicValue(m_options
.m_use_dynamic
).get();
131 m_valobj
= dynamic_value
;
133 m_valobj
= m_orig_valobj
;
135 m_valobj
= m_orig_valobj
;
138 if (m_valobj
->IsSynthetic()) {
139 if (!m_options
.m_use_synthetic
) {
140 ValueObject
*non_synthetic
= m_valobj
->GetNonSyntheticValue().get();
142 m_valobj
= non_synthetic
;
145 if (m_options
.m_use_synthetic
) {
146 ValueObject
*synthetic
= m_valobj
->GetSyntheticValue().get();
148 m_valobj
= synthetic
;
152 m_compiler_type
= m_valobj
->GetCompilerType();
153 m_type_flags
= m_compiler_type
.GetTypeInfo();
157 const char *ValueObjectPrinter::GetDescriptionForDisplay() {
158 const char *str
= m_valobj
->GetObjectDescription();
160 str
= m_valobj
->GetSummaryAsCString();
162 str
= m_valobj
->GetValueAsCString();
166 const char *ValueObjectPrinter::GetRootNameForDisplay() {
167 const char *root_valobj_name
= m_options
.m_root_valobj_name
.empty()
168 ? m_valobj
->GetName().AsCString()
169 : m_options
.m_root_valobj_name
.c_str();
170 return root_valobj_name
? root_valobj_name
: "";
173 bool ValueObjectPrinter::ShouldPrintValueObject() {
174 if (m_should_print
== eLazyBoolCalculate
)
176 (!m_options
.m_flat_output
|| m_type_flags
.Test(eTypeHasValue
))
179 return m_should_print
== eLazyBoolYes
;
182 bool ValueObjectPrinter::IsNil() {
183 if (m_is_nil
== eLazyBoolCalculate
)
184 m_is_nil
= m_valobj
->IsNilReference() ? eLazyBoolYes
: eLazyBoolNo
;
185 return m_is_nil
== eLazyBoolYes
;
188 bool ValueObjectPrinter::IsUninitialized() {
189 if (m_is_uninit
== eLazyBoolCalculate
)
191 m_valobj
->IsUninitializedReference() ? eLazyBoolYes
: eLazyBoolNo
;
192 return m_is_uninit
== eLazyBoolYes
;
195 bool ValueObjectPrinter::IsPtr() {
196 if (m_is_ptr
== eLazyBoolCalculate
)
197 m_is_ptr
= m_type_flags
.Test(eTypeIsPointer
) ? eLazyBoolYes
: eLazyBoolNo
;
198 return m_is_ptr
== eLazyBoolYes
;
201 bool ValueObjectPrinter::IsRef() {
202 if (m_is_ref
== eLazyBoolCalculate
)
203 m_is_ref
= m_type_flags
.Test(eTypeIsReference
) ? eLazyBoolYes
: eLazyBoolNo
;
204 return m_is_ref
== eLazyBoolYes
;
207 bool ValueObjectPrinter::IsAggregate() {
208 if (m_is_aggregate
== eLazyBoolCalculate
)
210 m_type_flags
.Test(eTypeHasChildren
) ? eLazyBoolYes
: eLazyBoolNo
;
211 return m_is_aggregate
== eLazyBoolYes
;
214 bool ValueObjectPrinter::IsInstancePointer() {
215 // you need to do this check on the value's clang type
216 if (m_is_instance_ptr
== eLazyBoolCalculate
)
217 m_is_instance_ptr
= (m_valobj
->GetValue().GetCompilerType().GetTypeInfo() &
218 eTypeInstanceIsPointer
) != 0
221 if ((eLazyBoolYes
== m_is_instance_ptr
) && m_valobj
->IsBaseClass())
222 m_is_instance_ptr
= eLazyBoolNo
;
223 return m_is_instance_ptr
== eLazyBoolYes
;
226 bool ValueObjectPrinter::PrintLocationIfNeeded() {
227 if (m_options
.m_show_location
) {
228 m_stream
->Printf("%s: ", m_valobj
->GetLocationAsCString());
234 void ValueObjectPrinter::PrintDecl() {
235 bool show_type
= true;
236 // if we are at the root-level and been asked to hide the root's type, then
238 if (m_curr_depth
== 0 && m_options
.m_hide_root_type
)
241 // otherwise decide according to the usual rules (asked to show types -
242 // always at the root level)
243 show_type
= m_options
.m_show_types
||
244 (m_curr_depth
== 0 && !m_options
.m_flat_output
);
246 StreamString typeName
;
248 // always show the type at the root level if it is invalid
250 // Some ValueObjects don't have types (like registers sets). Only print the
251 // type if there is one to print
252 ConstString type_name
;
253 if (m_compiler_type
.IsValid()) {
254 type_name
= m_options
.m_use_type_display_name
255 ? m_valobj
->GetDisplayTypeName()
256 : m_valobj
->GetQualifiedTypeName();
258 // only show an invalid type name if the user explicitly triggered
260 if (m_options
.m_show_types
)
261 type_name
= ConstString("<invalid type>");
265 std::string
type_name_str(type_name
.GetCString());
266 if (m_options
.m_hide_pointer_value
) {
267 for (auto iter
= type_name_str
.find(" *"); iter
!= std::string::npos
;
268 iter
= type_name_str
.find(" *")) {
269 type_name_str
.erase(iter
, 2);
272 typeName
<< type_name_str
.c_str();
276 StreamString varName
;
278 if (ShouldShowName()) {
279 if (m_options
.m_flat_output
)
280 m_valobj
->GetExpressionPath(varName
);
282 varName
<< GetRootNameForDisplay();
285 bool decl_printed
= false;
286 if (!m_options
.m_decl_printing_helper
) {
287 // if the user didn't give us a custom helper, pick one based upon the
288 // language, either the one that this printer is bound to, or the preferred
289 // one for the ValueObject
290 lldb::LanguageType lang_type
=
291 (m_options
.m_varformat_language
== lldb::eLanguageTypeUnknown
)
292 ? m_valobj
->GetPreferredDisplayLanguage()
293 : m_options
.m_varformat_language
;
294 if (Language
*lang_plugin
= Language::FindPlugin(lang_type
)) {
295 m_options
.m_decl_printing_helper
= lang_plugin
->GetDeclPrintingHelper();
299 if (m_options
.m_decl_printing_helper
) {
300 ConstString
type_name_cstr(typeName
.GetString());
301 ConstString
var_name_cstr(varName
.GetString());
303 DumpValueObjectOptions decl_print_options
= m_options
;
304 // Pass printing helpers an option object that indicates whether the name
305 // should be shown or hidden.
306 decl_print_options
.SetHideName(!ShouldShowName());
308 StreamString dest_stream
;
309 if (m_options
.m_decl_printing_helper(type_name_cstr
, var_name_cstr
,
310 decl_print_options
, dest_stream
)) {
312 m_stream
->PutCString(dest_stream
.GetString());
316 // if the helper failed, or there is none, do a default thing
318 if (!typeName
.Empty())
319 m_stream
->Printf("(%s) ", typeName
.GetData());
320 if (!varName
.Empty())
321 m_stream
->Printf("%s =", varName
.GetData());
322 else if (ShouldShowName())
323 m_stream
->Printf(" =");
327 bool ValueObjectPrinter::CheckScopeIfNeeded() {
328 if (m_options
.m_scope_already_checked
)
330 return m_valobj
->IsInScope();
333 TypeSummaryImpl
*ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted
) {
334 if (!m_summary_formatter
.second
) {
335 TypeSummaryImpl
*entry
= m_options
.m_summary_sp
336 ? m_options
.m_summary_sp
.get()
337 : m_valobj
->GetSummaryFormat().get();
339 if (m_options
.m_omit_summary_depth
> 0)
341 m_summary_formatter
.first
= entry
;
342 m_summary_formatter
.second
= true;
344 if (m_options
.m_omit_summary_depth
> 0 && null_if_omitted
)
346 return m_summary_formatter
.first
;
349 static bool IsPointerValue(const CompilerType
&type
) {
350 Flags
type_flags(type
.GetTypeInfo());
351 if (type_flags
.AnySet(eTypeInstanceIsPointer
| eTypeIsPointer
))
352 return type_flags
.AllClear(eTypeIsBuiltIn
);
356 void ValueObjectPrinter::GetValueSummaryError(std::string
&value
,
357 std::string
&summary
,
358 std::string
&error
) {
359 lldb::Format format
= m_options
.m_format
;
360 // if I am printing synthetized elements, apply the format to those elements
362 if (m_options
.m_pointer_as_array
)
363 m_valobj
->GetValueAsCString(lldb::eFormatDefault
, value
);
364 else if (format
!= eFormatDefault
&& format
!= m_valobj
->GetFormat())
365 m_valobj
->GetValueAsCString(format
, value
);
367 const char *val_cstr
= m_valobj
->GetValueAsCString();
369 value
.assign(val_cstr
);
371 const char *err_cstr
= m_valobj
->GetError().AsCString();
373 error
.assign(err_cstr
);
375 if (!ShouldPrintValueObject())
379 lldb::LanguageType lang_type
=
380 (m_options
.m_varformat_language
== lldb::eLanguageTypeUnknown
)
381 ? m_valobj
->GetPreferredDisplayLanguage()
382 : m_options
.m_varformat_language
;
383 if (Language
*lang_plugin
= Language::FindPlugin(lang_type
)) {
384 summary
.assign(lang_plugin
->GetNilReferenceSummaryString().str());
386 // We treat C as the fallback language rather than as a separate Language
388 summary
.assign("NULL");
390 } else if (IsUninitialized()) {
391 summary
.assign("<uninitialized>");
392 } else if (m_options
.m_omit_summary_depth
== 0) {
393 TypeSummaryImpl
*entry
= GetSummaryFormatter();
395 m_valobj
->GetSummaryAsCString(entry
, summary
,
396 m_options
.m_varformat_language
);
398 const char *sum_cstr
=
399 m_valobj
->GetSummaryAsCString(m_options
.m_varformat_language
);
401 summary
.assign(sum_cstr
);
406 bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed
,
407 bool &summary_printed
) {
408 bool error_printed
= false;
409 if (ShouldPrintValueObject()) {
410 if (!CheckScopeIfNeeded())
411 m_error
.assign("out of scope");
412 if (m_error
.empty()) {
413 GetValueSummaryError(m_value
, m_summary
, m_error
);
415 if (m_error
.size()) {
416 // we need to support scenarios in which it is actually fine for a value
417 // to have no type but - on the other hand - if we get an error *AND*
418 // have no type, we try to get out gracefully, since most often that
419 // combination means "could not resolve a type" and the default failure
420 // mode is quite ugly
421 if (!m_compiler_type
.IsValid()) {
422 m_stream
->Printf(" <could not resolve type>");
426 error_printed
= true;
427 m_stream
->Printf(" <%s>\n", m_error
.c_str());
429 // Make sure we have a value and make sure the summary didn't specify
430 // that the value should not be printed - and do not print the value if
431 // this thing is nil (but show the value if the user passes a format
433 TypeSummaryImpl
*entry
= GetSummaryFormatter();
434 const bool has_nil_or_uninitialized_summary
=
435 (IsNil() || IsUninitialized()) && !m_summary
.empty();
436 if (!has_nil_or_uninitialized_summary
&& !m_value
.empty() &&
438 (entry
->DoesPrintValue(m_valobj
) ||
439 m_options
.m_format
!= eFormatDefault
) ||
440 m_summary
.empty()) &&
441 !m_options
.m_hide_value
) {
442 if (m_options
.m_hide_pointer_value
&&
443 IsPointerValue(m_valobj
->GetCompilerType())) {
445 if (ShouldShowName())
446 m_stream
->PutChar(' ');
447 m_stream
->PutCString(m_value
);
448 value_printed
= true;
452 if (m_summary
.size()) {
453 if (ShouldShowName() || value_printed
)
454 m_stream
->PutChar(' ');
455 m_stream
->PutCString(m_summary
);
456 summary_printed
= true;
460 return !error_printed
;
463 bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed
,
464 bool summary_printed
) {
465 if (ShouldPrintValueObject()) {
466 // let's avoid the overly verbose no description error for a nil thing
467 if (m_options
.m_use_objc
&& !IsNil() && !IsUninitialized() &&
468 (!m_options
.m_pointer_as_array
)) {
469 if (!m_options
.m_hide_value
|| ShouldShowName())
470 m_stream
->Printf(" ");
471 const char *object_desc
= nullptr;
472 if (value_printed
|| summary_printed
)
473 object_desc
= m_valobj
->GetObjectDescription();
475 object_desc
= GetDescriptionForDisplay();
476 if (object_desc
&& *object_desc
) {
477 // If the description already ends with a \n don't add another one.
478 size_t object_end
= strlen(object_desc
) - 1;
479 if (object_desc
[object_end
] == '\n')
480 m_stream
->Printf("%s", object_desc
);
482 m_stream
->Printf("%s\n", object_desc
);
484 } else if (!value_printed
&& !summary_printed
)
493 bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
504 bool ValueObjectPrinter::ShouldPrintChildren(
505 DumpValueObjectOptions::PointerDepth
&curr_ptr_depth
) {
506 const bool is_ref
= IsRef();
507 const bool is_ptr
= IsPtr();
508 const bool is_uninit
= IsUninitialized();
513 // If we have reached the maximum depth we shouldn't print any more children.
514 if (HasReachedMaximumDepth())
517 // if the user has specified an element count, always print children as it is
518 // explicit user demand being honored
519 if (m_options
.m_pointer_as_array
)
522 if (m_options
.m_use_objc
)
525 bool print_children
= true;
526 if (TypeSummaryImpl
*type_summary
= GetSummaryFormatter())
527 print_children
= type_summary
->DoesPrintChildren(m_valobj
);
529 // We will show children for all concrete types. We won't show pointer
530 // contents unless a pointer depth has been specified. We won't reference
531 // contents unless the reference is the root object (depth of zero).
533 // Use a new temporary pointer depth in case we override the current
534 // pointer depth below...
536 if (is_ptr
|| is_ref
) {
537 // We have a pointer or reference whose value is an address. Make sure
538 // that address is not NULL
539 AddressType ptr_address_type
;
540 if (m_valobj
->GetPointerValue(&ptr_address_type
) == 0)
543 const bool is_root_level
= m_curr_depth
== 0;
545 if (is_ref
&& is_root_level
&& print_children
) {
546 // If this is the root object (depth is zero) that we are showing and
547 // it is a reference, and no pointer depth has been supplied print out
548 // what it references. Don't do this at deeper depths otherwise we can
549 // end up with infinite recursion...
553 return curr_ptr_depth
.CanAllowExpansion();
556 return print_children
|| m_summary
.empty();
559 bool ValueObjectPrinter::ShouldExpandEmptyAggregates() {
560 TypeSummaryImpl
*entry
= GetSummaryFormatter();
565 return entry
->DoesPrintEmptyAggregates();
568 ValueObject
*ValueObjectPrinter::GetValueObjectForChildrenGeneration() {
572 void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed
,
573 bool summary_printed
) {
574 if (m_options
.m_flat_output
) {
575 if (ShouldPrintValueObject())
578 if (ShouldPrintValueObject()) {
580 m_stream
->PutCString(": ");
581 } else if (value_printed
|| summary_printed
|| ShouldShowName()) {
582 m_stream
->PutChar(' ');
584 m_stream
->PutCString("{\n");
586 m_stream
->IndentMore();
590 void ValueObjectPrinter::PrintChild(
591 ValueObjectSP child_sp
,
592 const DumpValueObjectOptions::PointerDepth
&curr_ptr_depth
) {
593 const uint32_t consumed_summary_depth
= m_options
.m_pointer_as_array
? 0 : 1;
594 const bool does_consume_ptr_depth
=
595 ((IsPtr() && !m_options
.m_pointer_as_array
) || IsRef());
597 DumpValueObjectOptions
child_options(m_options
);
598 child_options
.SetFormat(m_options
.m_format
)
600 .SetRootValueObjectName();
601 child_options
.SetScopeChecked(true)
602 .SetHideName(m_options
.m_hide_name
)
603 .SetHideValue(m_options
.m_hide_value
)
604 .SetOmitSummaryDepth(child_options
.m_omit_summary_depth
> 1
605 ? child_options
.m_omit_summary_depth
-
606 consumed_summary_depth
610 if (child_sp
.get()) {
611 auto ptr_depth
= curr_ptr_depth
;
612 if (does_consume_ptr_depth
)
613 ptr_depth
= curr_ptr_depth
.Decremented();
615 ValueObjectPrinter
child_printer(child_sp
.get(), m_stream
, child_options
,
616 ptr_depth
, m_curr_depth
+ 1,
617 m_printed_instance_pointers
);
618 child_printer
.PrintValueObject();
622 uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot
) {
623 ValueObject
*synth_m_valobj
= GetValueObjectForChildrenGeneration();
625 if (m_options
.m_pointer_as_array
)
626 return m_options
.m_pointer_as_array
.m_element_count
;
628 size_t num_children
= synth_m_valobj
->GetNumChildren();
629 print_dotdotdot
= false;
631 const size_t max_num_children
=
632 m_valobj
->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
634 if (num_children
> max_num_children
&& !m_options
.m_ignore_cap
) {
635 print_dotdotdot
= true;
636 return max_num_children
;
642 void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot
) {
643 if (!m_options
.m_flat_output
) {
644 if (print_dotdotdot
) {
645 m_valobj
->GetTargetSP()
647 .GetCommandInterpreter()
648 .ChildrenTruncated();
649 m_stream
->Indent("...\n");
651 m_stream
->IndentLess();
652 m_stream
->Indent("}\n");
656 bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed
,
657 bool summary_printed
) {
658 ValueObject
*synth_m_valobj
= GetValueObjectForChildrenGeneration();
663 if (!m_options
.m_reveal_empty_aggregates
) {
664 if (value_printed
|| summary_printed
)
668 if (synth_m_valobj
->MightHaveChildren())
671 if (m_val_summary_ok
)
677 static constexpr size_t PhysicalIndexForLogicalIndex(size_t base
, size_t stride
,
679 return base
+ logical
* stride
;
682 ValueObjectSP
ValueObjectPrinter::GenerateChild(ValueObject
*synth_valobj
,
684 if (m_options
.m_pointer_as_array
) {
685 // if generating pointer-as-array children, use GetSyntheticArrayMember
686 return synth_valobj
->GetSyntheticArrayMember(
687 PhysicalIndexForLogicalIndex(
688 m_options
.m_pointer_as_array
.m_base_element
,
689 m_options
.m_pointer_as_array
.m_stride
, idx
),
692 // otherwise, do the usual thing
693 return synth_valobj
->GetChildAtIndex(idx
);
697 void ValueObjectPrinter::PrintChildren(
698 bool value_printed
, bool summary_printed
,
699 const DumpValueObjectOptions::PointerDepth
&curr_ptr_depth
) {
700 ValueObject
*synth_m_valobj
= GetValueObjectForChildrenGeneration();
702 bool print_dotdotdot
= false;
703 size_t num_children
= GetMaxNumChildrenToPrint(print_dotdotdot
);
705 bool any_children_printed
= false;
707 for (size_t idx
= 0; idx
< num_children
; ++idx
) {
708 if (ValueObjectSP child_sp
= GenerateChild(synth_m_valobj
, idx
)) {
709 if (m_options
.m_child_printing_decider
&&
710 !m_options
.m_child_printing_decider(child_sp
->GetName()))
712 if (!any_children_printed
) {
713 PrintChildrenPreamble(value_printed
, summary_printed
);
714 any_children_printed
= true;
716 PrintChild(child_sp
, curr_ptr_depth
);
720 if (any_children_printed
)
721 PrintChildrenPostamble(print_dotdotdot
);
723 if (ShouldPrintEmptyBrackets(value_printed
, summary_printed
)) {
724 if (ShouldPrintValueObject())
725 m_stream
->PutCString(" {}\n");
731 } else if (ShouldPrintEmptyBrackets(value_printed
, summary_printed
)) {
732 // Aggregate, no children...
733 if (ShouldPrintValueObject()) {
734 // if it has a synthetic value, then don't print {}, the synthetic
735 // children are probably only being used to vend a value
736 if (m_valobj
->DoesProvideSyntheticValue() ||
737 !ShouldExpandEmptyAggregates())
738 m_stream
->PutCString("\n");
740 m_stream
->PutCString(" {}\n");
743 if (ShouldPrintValueObject())
748 bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names
) {
749 if (!GetMostSpecializedValue() || m_valobj
== nullptr)
752 ValueObject
*synth_m_valobj
= GetValueObjectForChildrenGeneration();
754 bool print_dotdotdot
= false;
755 size_t num_children
= GetMaxNumChildrenToPrint(print_dotdotdot
);
758 m_stream
->PutChar('(');
760 bool did_print_children
= false;
761 for (uint32_t idx
= 0; idx
< num_children
; ++idx
) {
762 lldb::ValueObjectSP
child_sp(synth_m_valobj
->GetChildAtIndex(idx
));
764 child_sp
= child_sp
->GetQualifiedRepresentationIfAvailable(
765 m_options
.m_use_dynamic
, m_options
.m_use_synthetic
);
767 if (m_options
.m_child_printing_decider
&&
768 !m_options
.m_child_printing_decider(child_sp
->GetName()))
770 if (idx
&& did_print_children
)
771 m_stream
->PutCString(", ");
772 did_print_children
= true;
774 const char *name
= child_sp
.get()->GetName().AsCString();
776 m_stream
->PutCString(name
);
777 m_stream
->PutCString(" = ");
780 child_sp
->DumpPrintableRepresentation(
781 *m_stream
, ValueObject::eValueObjectRepresentationStyleSummary
,
783 ValueObject::PrintableRepresentationSpecialCases::eDisable
);
788 m_stream
->PutCString(", ...)");
790 m_stream
->PutChar(')');
795 void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed
,
796 bool summary_printed
) {
797 PrintObjectDescriptionIfNeeded(value_printed
, summary_printed
);
799 DumpValueObjectOptions::PointerDepth curr_ptr_depth
= m_ptr_depth
;
800 const bool print_children
= ShouldPrintChildren(curr_ptr_depth
);
801 const bool print_oneline
=
802 (curr_ptr_depth
.CanAllowExpansion() || m_options
.m_show_types
||
803 !m_options
.m_allow_oneliner_mode
|| m_options
.m_flat_output
||
804 (m_options
.m_pointer_as_array
) || m_options
.m_show_location
)
806 : DataVisualization::ShouldPrintAsOneLiner(*m_valobj
);
807 if (print_children
&& IsInstancePointer()) {
808 uint64_t instance_ptr_value
= m_valobj
->GetValueAsUnsigned(0);
809 if (m_printed_instance_pointers
->count(instance_ptr_value
)) {
810 // We already printed this instance-is-pointer thing, so don't expand it.
811 m_stream
->PutCString(" {...}\n");
814 // Remember this guy for future reference.
815 m_printed_instance_pointers
->emplace(instance_ptr_value
);
819 if (print_children
) {
821 m_stream
->PutChar(' ');
822 PrintChildrenOneLiner(false);
825 PrintChildren(value_printed
, summary_printed
, curr_ptr_depth
);
826 } else if (HasReachedMaximumDepth() && IsAggregate() &&
827 ShouldPrintValueObject()) {
828 m_stream
->PutCString("{...}\n");
829 // The maximum child depth has been reached. If `m_max_depth` is the default
830 // (i.e. the user has _not_ customized it), then lldb presents a warning to
831 // the user. The warning tells the user that the limit has been reached, but
832 // more importantly tells them how to expand the limit if desired.
833 if (m_options
.m_max_depth_is_default
)
834 m_valobj
->GetTargetSP()
836 .GetCommandInterpreter()
837 .SetReachedMaximumDepth();
842 bool ValueObjectPrinter::HasReachedMaximumDepth() {
843 return m_curr_depth
>= m_options
.m_max_depth
;
846 bool ValueObjectPrinter::ShouldShowName() const {
847 if (m_curr_depth
== 0)
848 return !m_options
.m_hide_root_name
&& !m_options
.m_hide_name
;
849 return !m_options
.m_hide_name
;