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/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 "lldb/ValueObject/ValueObject.h"
17 #include "llvm/Support/MathExtras.h"
21 using namespace lldb_private
;
23 ValueObjectPrinter::ValueObjectPrinter(ValueObject
&valobj
, Stream
*s
)
24 : m_orig_valobj(valobj
) {
25 DumpValueObjectOptions
options(valobj
);
26 Init(valobj
, s
, options
, m_options
.m_max_ptr_depth
, 0, nullptr);
29 ValueObjectPrinter::ValueObjectPrinter(ValueObject
&valobj
, Stream
*s
,
30 const DumpValueObjectOptions
&options
)
31 : m_orig_valobj(valobj
) {
32 Init(valobj
, s
, options
, m_options
.m_max_ptr_depth
, 0, nullptr);
35 ValueObjectPrinter::ValueObjectPrinter(
36 ValueObject
&valobj
, Stream
*s
, const DumpValueObjectOptions
&options
,
37 const DumpValueObjectOptions::PointerDepth
&ptr_depth
, uint32_t curr_depth
,
38 InstancePointersSetSP printed_instance_pointers
)
39 : m_orig_valobj(valobj
) {
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_cached_valobj
= nullptr;
50 m_ptr_depth
= ptr_depth
;
51 m_curr_depth
= curr_depth
;
52 assert(m_stream
&& "cannot print to a NULL Stream");
53 m_should_print
= eLazyBoolCalculate
;
54 m_is_nil
= eLazyBoolCalculate
;
55 m_is_uninit
= eLazyBoolCalculate
;
56 m_is_ptr
= eLazyBoolCalculate
;
57 m_is_ref
= eLazyBoolCalculate
;
58 m_is_aggregate
= eLazyBoolCalculate
;
59 m_is_instance_ptr
= eLazyBoolCalculate
;
60 m_summary_formatter
= {nullptr, false};
64 m_val_summary_ok
= false;
65 m_printed_instance_pointers
=
66 printed_instance_pointers
67 ? printed_instance_pointers
68 : InstancePointersSetSP(new InstancePointersSet());
69 SetupMostSpecializedValue();
72 llvm::Error
ValueObjectPrinter::PrintValueObject() {
73 // If the incoming ValueObject is in an error state, the best we're going to
74 // get out of it is its type. But if we don't even have that, just print
75 // the error and exit early.
76 if (m_orig_valobj
.GetError().Fail() &&
77 !m_orig_valobj
.GetCompilerType().IsValid())
78 return m_orig_valobj
.GetError().ToError();
80 if (ShouldPrintValueObject()) {
81 PrintLocationIfNeeded();
87 bool value_printed
= false;
88 bool summary_printed
= false;
91 PrintValueAndSummaryIfNeeded(value_printed
, summary_printed
);
94 return PrintChildrenIfNeeded(value_printed
, summary_printed
);
97 return llvm::Error::success();
100 ValueObject
&ValueObjectPrinter::GetMostSpecializedValue() {
101 assert(m_cached_valobj
&& "ValueObjectPrinter must have a valid ValueObject");
102 return *m_cached_valobj
;
105 void ValueObjectPrinter::SetupMostSpecializedValue() {
106 bool update_success
= m_orig_valobj
.UpdateValueIfNeeded(true);
107 // If we can't find anything better, we'll fall back on the original
109 m_cached_valobj
= &m_orig_valobj
;
110 if (update_success
) {
111 if (m_orig_valobj
.IsDynamic()) {
112 if (m_options
.m_use_dynamic
== eNoDynamicValues
) {
113 ValueObject
*static_value
= m_orig_valobj
.GetStaticValue().get();
115 m_cached_valobj
= static_value
;
118 if (m_options
.m_use_dynamic
!= eNoDynamicValues
) {
119 ValueObject
*dynamic_value
=
120 m_orig_valobj
.GetDynamicValue(m_options
.m_use_dynamic
).get();
122 m_cached_valobj
= dynamic_value
;
126 if (m_cached_valobj
->IsSynthetic()) {
127 if (!m_options
.m_use_synthetic
) {
128 ValueObject
*non_synthetic
=
129 m_cached_valobj
->GetNonSyntheticValue().get();
131 m_cached_valobj
= non_synthetic
;
134 if (m_options
.m_use_synthetic
) {
135 ValueObject
*synthetic
= m_cached_valobj
->GetSyntheticValue().get();
137 m_cached_valobj
= synthetic
;
141 m_compiler_type
= m_cached_valobj
->GetCompilerType();
142 m_type_flags
= m_compiler_type
.GetTypeInfo();
143 assert(m_cached_valobj
&&
144 "SetupMostSpecialized value must compute a valid ValueObject");
147 llvm::Expected
<std::string
> ValueObjectPrinter::GetDescriptionForDisplay() {
148 ValueObject
&valobj
= GetMostSpecializedValue();
149 llvm::Expected
<std::string
> maybe_str
= valobj
.GetObjectDescription();
153 const char *str
= nullptr;
155 str
= valobj
.GetSummaryAsCString();
157 str
= valobj
.GetValueAsCString();
161 llvm::consumeError(maybe_str
.takeError());
165 const char *ValueObjectPrinter::GetRootNameForDisplay() {
166 const char *root_valobj_name
=
167 m_options
.m_root_valobj_name
.empty()
168 ? GetMostSpecializedValue().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
)
185 GetMostSpecializedValue().IsNilReference() ? eLazyBoolYes
: eLazyBoolNo
;
186 return m_is_nil
== eLazyBoolYes
;
189 bool ValueObjectPrinter::IsUninitialized() {
190 if (m_is_uninit
== eLazyBoolCalculate
)
191 m_is_uninit
= GetMostSpecializedValue().IsUninitializedReference()
194 return m_is_uninit
== eLazyBoolYes
;
197 bool ValueObjectPrinter::IsPtr() {
198 if (m_is_ptr
== eLazyBoolCalculate
)
199 m_is_ptr
= m_type_flags
.Test(eTypeIsPointer
) ? eLazyBoolYes
: eLazyBoolNo
;
200 return m_is_ptr
== eLazyBoolYes
;
203 bool ValueObjectPrinter::IsRef() {
204 if (m_is_ref
== eLazyBoolCalculate
)
205 m_is_ref
= m_type_flags
.Test(eTypeIsReference
) ? eLazyBoolYes
: eLazyBoolNo
;
206 return m_is_ref
== eLazyBoolYes
;
209 bool ValueObjectPrinter::IsAggregate() {
210 if (m_is_aggregate
== eLazyBoolCalculate
)
212 m_type_flags
.Test(eTypeHasChildren
) ? eLazyBoolYes
: eLazyBoolNo
;
213 return m_is_aggregate
== eLazyBoolYes
;
216 bool ValueObjectPrinter::IsInstancePointer() {
217 // you need to do this check on the value's clang type
218 ValueObject
&valobj
= GetMostSpecializedValue();
219 if (m_is_instance_ptr
== eLazyBoolCalculate
)
220 m_is_instance_ptr
= (valobj
.GetValue().GetCompilerType().GetTypeInfo() &
221 eTypeInstanceIsPointer
) != 0
224 if ((eLazyBoolYes
== m_is_instance_ptr
) && valobj
.IsBaseClass())
225 m_is_instance_ptr
= eLazyBoolNo
;
226 return m_is_instance_ptr
== eLazyBoolYes
;
229 bool ValueObjectPrinter::PrintLocationIfNeeded() {
230 if (m_options
.m_show_location
) {
231 m_stream
->Printf("%s: ", GetMostSpecializedValue().GetLocationAsCString());
237 void ValueObjectPrinter::PrintDecl() {
238 bool show_type
= true;
239 // if we are at the root-level and been asked to hide the root's type, then
241 if (m_curr_depth
== 0 && m_options
.m_hide_root_type
)
244 // otherwise decide according to the usual rules (asked to show types -
245 // always at the root level)
246 show_type
= m_options
.m_show_types
||
247 (m_curr_depth
== 0 && !m_options
.m_flat_output
);
249 StreamString typeName
;
250 // Figure out which ValueObject we're acting on
251 ValueObject
&valobj
= GetMostSpecializedValue();
253 // always show the type at the root level if it is invalid
255 // Some ValueObjects don't have types (like registers sets). Only print the
256 // type if there is one to print
257 ConstString type_name
;
258 if (m_compiler_type
.IsValid()) {
259 type_name
= m_options
.m_use_type_display_name
260 ? valobj
.GetDisplayTypeName()
261 : valobj
.GetQualifiedTypeName();
263 // only show an invalid type name if the user explicitly triggered
265 if (m_options
.m_show_types
)
266 type_name
= ConstString("<invalid type>");
270 std::string
type_name_str(type_name
.GetCString());
271 if (m_options
.m_hide_pointer_value
) {
272 for (auto iter
= type_name_str
.find(" *"); iter
!= std::string::npos
;
273 iter
= type_name_str
.find(" *")) {
274 type_name_str
.erase(iter
, 2);
277 typeName
<< type_name_str
.c_str();
281 StreamString varName
;
283 if (ShouldShowName()) {
284 if (m_options
.m_flat_output
)
285 valobj
.GetExpressionPath(varName
);
287 varName
<< GetRootNameForDisplay();
290 bool decl_printed
= false;
291 if (!m_options
.m_decl_printing_helper
) {
292 // if the user didn't give us a custom helper, pick one based upon the
293 // language, either the one that this printer is bound to, or the preferred
294 // one for the ValueObject
295 lldb::LanguageType lang_type
=
296 (m_options
.m_varformat_language
== lldb::eLanguageTypeUnknown
)
297 ? valobj
.GetPreferredDisplayLanguage()
298 : m_options
.m_varformat_language
;
299 if (Language
*lang_plugin
= Language::FindPlugin(lang_type
)) {
300 m_options
.m_decl_printing_helper
= lang_plugin
->GetDeclPrintingHelper();
304 if (m_options
.m_decl_printing_helper
) {
305 ConstString
type_name_cstr(typeName
.GetString());
306 ConstString
var_name_cstr(varName
.GetString());
308 DumpValueObjectOptions decl_print_options
= m_options
;
309 // Pass printing helpers an option object that indicates whether the name
310 // should be shown or hidden.
311 decl_print_options
.SetHideName(!ShouldShowName());
313 StreamString dest_stream
;
314 if (m_options
.m_decl_printing_helper(type_name_cstr
, var_name_cstr
,
315 decl_print_options
, dest_stream
)) {
317 m_stream
->PutCString(dest_stream
.GetString());
321 // if the helper failed, or there is none, do a default thing
323 if (!typeName
.Empty())
324 m_stream
->Printf("(%s) ", typeName
.GetData());
325 if (!varName
.Empty())
326 m_stream
->Printf("%s =", varName
.GetData());
327 else if (ShouldShowName())
328 m_stream
->Printf(" =");
332 bool ValueObjectPrinter::CheckScopeIfNeeded() {
333 if (m_options
.m_scope_already_checked
)
335 return GetMostSpecializedValue().IsInScope();
338 TypeSummaryImpl
*ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted
) {
339 if (!m_summary_formatter
.second
) {
340 TypeSummaryImpl
*entry
=
341 m_options
.m_summary_sp
342 ? m_options
.m_summary_sp
.get()
343 : GetMostSpecializedValue().GetSummaryFormat().get();
345 if (m_options
.m_omit_summary_depth
> 0)
347 m_summary_formatter
.first
= entry
;
348 m_summary_formatter
.second
= true;
350 if (m_options
.m_omit_summary_depth
> 0 && null_if_omitted
)
352 return m_summary_formatter
.first
;
355 static bool IsPointerValue(const CompilerType
&type
) {
356 Flags
type_flags(type
.GetTypeInfo());
357 if (type_flags
.AnySet(eTypeInstanceIsPointer
| eTypeIsPointer
))
358 return type_flags
.AllClear(eTypeIsBuiltIn
);
362 void ValueObjectPrinter::GetValueSummaryError(std::string
&value
,
363 std::string
&summary
,
364 std::string
&error
) {
365 lldb::Format format
= m_options
.m_format
;
366 ValueObject
&valobj
= GetMostSpecializedValue();
367 // if I am printing synthetized elements, apply the format to those elements
369 if (m_options
.m_pointer_as_array
)
370 valobj
.GetValueAsCString(lldb::eFormatDefault
, value
);
371 else if (format
!= eFormatDefault
&& format
!= valobj
.GetFormat())
372 valobj
.GetValueAsCString(format
, value
);
374 const char *val_cstr
= valobj
.GetValueAsCString();
376 value
.assign(val_cstr
);
378 const char *err_cstr
= valobj
.GetError().AsCString();
380 error
.assign(err_cstr
);
382 if (!ShouldPrintValueObject())
386 lldb::LanguageType lang_type
=
387 (m_options
.m_varformat_language
== lldb::eLanguageTypeUnknown
)
388 ? valobj
.GetPreferredDisplayLanguage()
389 : m_options
.m_varformat_language
;
390 if (Language
*lang_plugin
= Language::FindPlugin(lang_type
)) {
391 summary
.assign(lang_plugin
->GetNilReferenceSummaryString().str());
393 // We treat C as the fallback language rather than as a separate Language
395 summary
.assign("NULL");
397 } else if (IsUninitialized()) {
398 summary
.assign("<uninitialized>");
399 } else if (m_options
.m_omit_summary_depth
== 0) {
400 TypeSummaryImpl
*entry
= GetSummaryFormatter();
402 valobj
.GetSummaryAsCString(entry
, summary
,
403 m_options
.m_varformat_language
);
405 const char *sum_cstr
=
406 valobj
.GetSummaryAsCString(m_options
.m_varformat_language
);
408 summary
.assign(sum_cstr
);
413 bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed
,
414 bool &summary_printed
) {
415 bool error_printed
= false;
416 if (ShouldPrintValueObject()) {
417 if (!CheckScopeIfNeeded())
418 m_error
.assign("out of scope");
419 if (m_error
.empty()) {
420 GetValueSummaryError(m_value
, m_summary
, m_error
);
422 if (m_error
.size()) {
423 // we need to support scenarios in which it is actually fine for a value
424 // to have no type but - on the other hand - if we get an error *AND*
425 // have no type, we try to get out gracefully, since most often that
426 // combination means "could not resolve a type" and the default failure
427 // mode is quite ugly
428 if (!m_compiler_type
.IsValid()) {
429 m_stream
->Printf(" <could not resolve type>");
433 error_printed
= true;
434 m_stream
->Printf(" <%s>\n", m_error
.c_str());
436 // Make sure we have a value and make sure the summary didn't specify
437 // that the value should not be printed - and do not print the value if
438 // this thing is nil (but show the value if the user passes a format
440 TypeSummaryImpl
*entry
= GetSummaryFormatter();
441 ValueObject
&valobj
= GetMostSpecializedValue();
442 const bool has_nil_or_uninitialized_summary
=
443 (IsNil() || IsUninitialized()) && !m_summary
.empty();
444 if (!has_nil_or_uninitialized_summary
&& !m_value
.empty() &&
446 (entry
->DoesPrintValue(&valobj
) ||
447 m_options
.m_format
!= eFormatDefault
) ||
448 m_summary
.empty()) &&
449 !m_options
.m_hide_value
) {
450 if (m_options
.m_hide_pointer_value
&&
451 IsPointerValue(valobj
.GetCompilerType())) {
453 if (ShouldShowName())
454 m_stream
->PutChar(' ');
455 m_stream
->PutCString(m_value
);
456 value_printed
= true;
460 if (m_summary
.size()) {
461 if (ShouldShowName() || value_printed
)
462 m_stream
->PutChar(' ');
463 m_stream
->PutCString(m_summary
);
464 summary_printed
= true;
468 return !error_printed
;
472 ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed
,
473 bool summary_printed
) {
474 if (ShouldPrintValueObject()) {
475 // let's avoid the overly verbose no description error for a nil thing
476 if (m_options
.m_use_objc
&& !IsNil() && !IsUninitialized() &&
477 (!m_options
.m_pointer_as_array
)) {
478 if (!m_options
.m_hide_value
|| ShouldShowName())
480 llvm::Expected
<std::string
> object_desc
=
481 (value_printed
|| summary_printed
)
482 ? GetMostSpecializedValue().GetObjectDescription()
483 : GetDescriptionForDisplay();
485 // If no value or summary was printed, surface the error.
486 if (!value_printed
&& !summary_printed
)
487 return object_desc
.takeError();
488 // Otherwise gently nudge the user that they should have used
489 // `p` instead of `po`. Unfortunately we cannot be more direct
490 // about this, because we don't actually know what the user did.
491 *m_stream
<< "warning: no object description available\n";
492 llvm::consumeError(object_desc
.takeError());
494 *m_stream
<< *object_desc
;
495 // If the description already ends with a \n don't add another one.
496 if (object_desc
->empty() || object_desc
->back() != '\n')
499 return llvm::Error::success();
502 return llvm::Error::success();
505 bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
509 bool ValueObjectPrinter::ShouldPrintChildren(
510 DumpValueObjectOptions::PointerDepth
&curr_ptr_depth
) {
511 const bool is_ref
= IsRef();
512 const bool is_ptr
= IsPtr();
513 const bool is_uninit
= IsUninitialized();
518 // If we have reached the maximum depth we shouldn't print any more children.
519 if (HasReachedMaximumDepth())
522 // if the user has specified an element count, always print children as it is
523 // explicit user demand being honored
524 if (m_options
.m_pointer_as_array
)
527 if (m_options
.m_use_objc
)
530 bool print_children
= true;
531 ValueObject
&valobj
= GetMostSpecializedValue();
532 if (TypeSummaryImpl
*type_summary
= GetSummaryFormatter())
533 print_children
= type_summary
->DoesPrintChildren(&valobj
);
535 // We will show children for all concrete types. We won't show pointer
536 // contents unless a pointer depth has been specified. We won't reference
537 // contents unless the reference is the root object (depth of zero).
539 // Use a new temporary pointer depth in case we override the current
540 // pointer depth below...
542 if (is_ptr
|| is_ref
) {
543 // We have a pointer or reference whose value is an address. Make sure
544 // that address is not NULL
545 AddressType ptr_address_type
;
546 if (valobj
.GetPointerValue(&ptr_address_type
) == 0)
549 const bool is_root_level
= m_curr_depth
== 0;
551 if (is_ref
&& is_root_level
&& print_children
) {
552 // If this is the root object (depth is zero) that we are showing and
553 // it is a reference, and no pointer depth has been supplied print out
554 // what it references. Don't do this at deeper depths otherwise we can
555 // end up with infinite recursion...
559 return curr_ptr_depth
.CanAllowExpansion();
562 return print_children
|| m_summary
.empty();
565 bool ValueObjectPrinter::ShouldExpandEmptyAggregates() {
566 TypeSummaryImpl
*entry
= GetSummaryFormatter();
571 return entry
->DoesPrintEmptyAggregates();
574 ValueObject
&ValueObjectPrinter::GetValueObjectForChildrenGeneration() {
575 return GetMostSpecializedValue();
578 void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed
,
579 bool summary_printed
) {
580 if (m_options
.m_flat_output
) {
581 if (ShouldPrintValueObject())
584 if (ShouldPrintValueObject()) {
586 m_stream
->PutCString(": ");
587 } else if (value_printed
|| summary_printed
|| ShouldShowName()) {
588 m_stream
->PutChar(' ');
590 m_stream
->PutCString("{\n");
592 m_stream
->IndentMore();
596 void ValueObjectPrinter::PrintChild(
597 ValueObjectSP child_sp
,
598 const DumpValueObjectOptions::PointerDepth
&curr_ptr_depth
) {
599 const uint32_t consumed_summary_depth
= m_options
.m_pointer_as_array
? 0 : 1;
600 const bool does_consume_ptr_depth
=
601 ((IsPtr() && !m_options
.m_pointer_as_array
) || IsRef());
603 DumpValueObjectOptions
child_options(m_options
);
604 child_options
.SetFormat(m_options
.m_format
)
606 .SetRootValueObjectName();
607 child_options
.SetScopeChecked(true)
608 .SetHideName(m_options
.m_hide_name
)
609 .SetHideValue(m_options
.m_hide_value
)
610 .SetOmitSummaryDepth(child_options
.m_omit_summary_depth
> 1
611 ? child_options
.m_omit_summary_depth
-
612 consumed_summary_depth
616 if (child_sp
.get()) {
617 auto ptr_depth
= curr_ptr_depth
;
618 if (does_consume_ptr_depth
)
619 ptr_depth
= curr_ptr_depth
.Decremented();
621 ValueObjectPrinter
child_printer(*(child_sp
.get()), m_stream
, child_options
,
622 ptr_depth
, m_curr_depth
+ 1,
623 m_printed_instance_pointers
);
624 llvm::Error error
= child_printer
.PrintValueObject();
627 *m_stream
<< "error: " << toString(std::move(error
));
629 llvm::consumeError(std::move(error
));
634 llvm::Expected
<uint32_t>
635 ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot
) {
636 ValueObject
&synth_valobj
= GetValueObjectForChildrenGeneration();
638 if (m_options
.m_pointer_as_array
)
639 return m_options
.m_pointer_as_array
.m_element_count
;
641 const uint32_t max_num_children
=
642 m_options
.m_ignore_cap
? UINT32_MAX
643 : GetMostSpecializedValue()
645 ->GetMaximumNumberOfChildrenToDisplay();
646 // Ask for one more child than the maximum to see if we should print "...".
647 auto num_children_or_err
= synth_valobj
.GetNumChildren(
648 llvm::SaturatingAdd(max_num_children
, uint32_t(1)));
649 if (!num_children_or_err
)
650 return num_children_or_err
;
651 if (*num_children_or_err
> max_num_children
) {
652 print_dotdotdot
= true;
653 return max_num_children
;
655 return num_children_or_err
;
658 void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot
) {
659 if (!m_options
.m_flat_output
) {
660 if (print_dotdotdot
) {
661 GetMostSpecializedValue()
664 .GetCommandInterpreter()
665 .ChildrenTruncated();
666 m_stream
->Indent("...\n");
668 m_stream
->IndentLess();
669 m_stream
->Indent("}\n");
673 bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed
,
674 bool summary_printed
) {
675 ValueObject
&synth_valobj
= GetValueObjectForChildrenGeneration();
680 if (!m_options
.m_reveal_empty_aggregates
) {
681 if (value_printed
|| summary_printed
)
685 if (synth_valobj
.MightHaveChildren())
688 if (m_val_summary_ok
)
694 static constexpr size_t PhysicalIndexForLogicalIndex(size_t base
, size_t stride
,
696 return base
+ logical
* stride
;
699 ValueObjectSP
ValueObjectPrinter::GenerateChild(ValueObject
&synth_valobj
,
701 if (m_options
.m_pointer_as_array
) {
702 // if generating pointer-as-array children, use GetSyntheticArrayMember
703 return synth_valobj
.GetSyntheticArrayMember(
704 PhysicalIndexForLogicalIndex(
705 m_options
.m_pointer_as_array
.m_base_element
,
706 m_options
.m_pointer_as_array
.m_stride
, idx
),
709 // otherwise, do the usual thing
710 return synth_valobj
.GetChildAtIndex(idx
);
714 void ValueObjectPrinter::PrintChildren(
715 bool value_printed
, bool summary_printed
,
716 const DumpValueObjectOptions::PointerDepth
&curr_ptr_depth
) {
717 ValueObject
&synth_valobj
= GetValueObjectForChildrenGeneration();
719 bool print_dotdotdot
= false;
720 auto num_children_or_err
= GetMaxNumChildrenToPrint(print_dotdotdot
);
721 if (!num_children_or_err
) {
722 *m_stream
<< " <" << llvm::toString(num_children_or_err
.takeError()) << '>';
725 uint32_t num_children
= *num_children_or_err
;
727 bool any_children_printed
= false;
729 for (size_t idx
= 0; idx
< num_children
; ++idx
) {
730 if (ValueObjectSP child_sp
= GenerateChild(synth_valobj
, idx
)) {
731 if (m_options
.m_child_printing_decider
&&
732 !m_options
.m_child_printing_decider(child_sp
->GetName()))
734 if (!any_children_printed
) {
735 PrintChildrenPreamble(value_printed
, summary_printed
);
736 any_children_printed
= true;
738 PrintChild(child_sp
, curr_ptr_depth
);
742 if (any_children_printed
)
743 PrintChildrenPostamble(print_dotdotdot
);
745 if (ShouldPrintEmptyBrackets(value_printed
, summary_printed
)) {
746 if (ShouldPrintValueObject())
747 m_stream
->PutCString(" {}\n");
753 } else if (ShouldPrintEmptyBrackets(value_printed
, summary_printed
)) {
754 // Aggregate, no children...
755 if (ShouldPrintValueObject()) {
756 // if it has a synthetic value, then don't print {}, the synthetic
757 // children are probably only being used to vend a value
758 if (GetMostSpecializedValue().DoesProvideSyntheticValue() ||
759 !ShouldExpandEmptyAggregates())
760 m_stream
->PutCString("\n");
762 m_stream
->PutCString(" {}\n");
765 if (ShouldPrintValueObject())
770 bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names
) {
771 ValueObject
&synth_valobj
= GetValueObjectForChildrenGeneration();
773 bool print_dotdotdot
= false;
774 auto num_children_or_err
= GetMaxNumChildrenToPrint(print_dotdotdot
);
775 if (!num_children_or_err
) {
776 *m_stream
<< '<' << llvm::toString(num_children_or_err
.takeError()) << '>';
779 uint32_t num_children
= *num_children_or_err
;
782 m_stream
->PutChar('(');
784 bool did_print_children
= false;
785 for (uint32_t idx
= 0; idx
< num_children
; ++idx
) {
786 lldb::ValueObjectSP
child_sp(synth_valobj
.GetChildAtIndex(idx
));
788 child_sp
= child_sp
->GetQualifiedRepresentationIfAvailable(
789 m_options
.m_use_dynamic
, m_options
.m_use_synthetic
);
791 if (m_options
.m_child_printing_decider
&&
792 !m_options
.m_child_printing_decider(child_sp
->GetName()))
794 if (idx
&& did_print_children
)
795 m_stream
->PutCString(", ");
796 did_print_children
= true;
798 const char *name
= child_sp
.get()->GetName().AsCString();
800 m_stream
->PutCString(name
);
801 m_stream
->PutCString(" = ");
804 child_sp
->DumpPrintableRepresentation(
805 *m_stream
, ValueObject::eValueObjectRepresentationStyleSummary
,
807 ValueObject::PrintableRepresentationSpecialCases::eDisable
);
812 m_stream
->PutCString(", ...)");
814 m_stream
->PutChar(')');
819 llvm::Error
ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed
,
820 bool summary_printed
) {
821 auto error
= PrintObjectDescriptionIfNeeded(value_printed
, summary_printed
);
825 ValueObject
&valobj
= GetMostSpecializedValue();
827 DumpValueObjectOptions::PointerDepth curr_ptr_depth
= m_ptr_depth
;
828 const bool print_children
= ShouldPrintChildren(curr_ptr_depth
);
829 const bool print_oneline
=
830 (curr_ptr_depth
.CanAllowExpansion() || m_options
.m_show_types
||
831 !m_options
.m_allow_oneliner_mode
|| m_options
.m_flat_output
||
832 (m_options
.m_pointer_as_array
) || m_options
.m_show_location
)
834 : DataVisualization::ShouldPrintAsOneLiner(valobj
);
835 if (print_children
&& IsInstancePointer()) {
836 uint64_t instance_ptr_value
= valobj
.GetValueAsUnsigned(0);
837 if (m_printed_instance_pointers
->count(instance_ptr_value
)) {
838 // We already printed this instance-is-pointer thing, so don't expand it.
839 m_stream
->PutCString(" {...}\n");
840 return llvm::Error::success();
842 // Remember this guy for future reference.
843 m_printed_instance_pointers
->emplace(instance_ptr_value
);
847 if (print_children
) {
849 m_stream
->PutChar(' ');
850 PrintChildrenOneLiner(false);
853 PrintChildren(value_printed
, summary_printed
, curr_ptr_depth
);
854 } else if (HasReachedMaximumDepth() && IsAggregate() &&
855 ShouldPrintValueObject()) {
856 m_stream
->PutCString("{...}\n");
857 // The maximum child depth has been reached. If `m_max_depth` is the default
858 // (i.e. the user has _not_ customized it), then lldb presents a warning to
859 // the user. The warning tells the user that the limit has been reached, but
860 // more importantly tells them how to expand the limit if desired.
861 if (m_options
.m_max_depth_is_default
)
864 .GetCommandInterpreter()
865 .SetReachedMaximumDepth();
868 return llvm::Error::success();
871 bool ValueObjectPrinter::HasReachedMaximumDepth() {
872 return m_curr_depth
>= m_options
.m_max_depth
;
875 bool ValueObjectPrinter::ShouldShowName() const {
876 if (m_curr_depth
== 0)
877 return !m_options
.m_hide_root_name
&& !m_options
.m_hide_name
;
878 return !m_options
.m_hide_name
;