ValueObjectPrinter.cpp revision 360660
1//===-- ValueObjectPrinter.cpp -----------------------------------*- C++-*-===// 2// 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 6// 7//===----------------------------------------------------------------------===// 8 9#include "lldb/DataFormatters/ValueObjectPrinter.h" 10 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" 17 18using namespace lldb; 19using namespace lldb_private; 20 21ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s) { 22 if (valobj) { 23 DumpValueObjectOptions options(*valobj); 24 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 25 } else { 26 DumpValueObjectOptions options; 27 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 28 } 29} 30 31ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s, 32 const DumpValueObjectOptions &options) { 33 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 34} 35 36ValueObjectPrinter::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); 41} 42 43void 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; 48 m_valobj = nullptr; 49 m_stream = s; 50 m_options = options; 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}; 63 m_value.assign(""); 64 m_summary.assign(""); 65 m_error.assign(""); 66 m_val_summary_ok = false; 67 m_printed_instance_pointers = 68 printed_instance_pointers 69 ? printed_instance_pointers 70 : InstancePointersSetSP(new InstancePointersSet()); 71} 72 73bool ValueObjectPrinter::PrintValueObject() { 74 if (!GetMostSpecializedValue() || m_valobj == nullptr) 75 return false; 76 77 if (ShouldPrintValueObject()) { 78 PrintValidationMarkerIfNeeded(); 79 80 PrintLocationIfNeeded(); 81 m_stream->Indent(); 82 83 PrintDecl(); 84 } 85 86 bool value_printed = false; 87 bool summary_printed = false; 88 89 m_val_summary_ok = 90 PrintValueAndSummaryIfNeeded(value_printed, summary_printed); 91 92 if (m_val_summary_ok) 93 PrintChildrenIfNeeded(value_printed, summary_printed); 94 else 95 m_stream->EOL(); 96 97 PrintValidationErrorIfNeeded(); 98 99 return true; 100} 101 102bool ValueObjectPrinter::GetMostSpecializedValue() { 103 if (m_valobj) 104 return true; 105 bool update_success = m_orig_valobj->UpdateValueIfNeeded(true); 106 if (!update_success) { 107 m_valobj = m_orig_valobj; 108 } else { 109 if (m_orig_valobj->IsDynamic()) { 110 if (m_options.m_use_dynamic == eNoDynamicValues) { 111 ValueObject *static_value = m_orig_valobj->GetStaticValue().get(); 112 if (static_value) 113 m_valobj = static_value; 114 else 115 m_valobj = m_orig_valobj; 116 } else 117 m_valobj = m_orig_valobj; 118 } else { 119 if (m_options.m_use_dynamic != eNoDynamicValues) { 120 ValueObject *dynamic_value = 121 m_orig_valobj->GetDynamicValue(m_options.m_use_dynamic).get(); 122 if (dynamic_value) 123 m_valobj = dynamic_value; 124 else 125 m_valobj = m_orig_valobj; 126 } else 127 m_valobj = m_orig_valobj; 128 } 129 130 if (m_valobj->IsSynthetic()) { 131 if (!m_options.m_use_synthetic) { 132 ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); 133 if (non_synthetic) 134 m_valobj = non_synthetic; 135 } 136 } else { 137 if (m_options.m_use_synthetic) { 138 ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); 139 if (synthetic) 140 m_valobj = synthetic; 141 } 142 } 143 } 144 m_compiler_type = m_valobj->GetCompilerType(); 145 m_type_flags = m_compiler_type.GetTypeInfo(); 146 return true; 147} 148 149const char *ValueObjectPrinter::GetDescriptionForDisplay() { 150 const char *str = m_valobj->GetObjectDescription(); 151 if (!str) 152 str = m_valobj->GetSummaryAsCString(); 153 if (!str) 154 str = m_valobj->GetValueAsCString(); 155 return str; 156} 157 158const char *ValueObjectPrinter::GetRootNameForDisplay(const char *if_fail) { 159 const char *root_valobj_name = m_options.m_root_valobj_name.empty() 160 ? m_valobj->GetName().AsCString() 161 : m_options.m_root_valobj_name.c_str(); 162 return root_valobj_name ? root_valobj_name : if_fail; 163} 164 165bool ValueObjectPrinter::ShouldPrintValueObject() { 166 if (m_should_print == eLazyBoolCalculate) 167 m_should_print = 168 (!m_options.m_flat_output || m_type_flags.Test(eTypeHasValue)) 169 ? eLazyBoolYes 170 : eLazyBoolNo; 171 return m_should_print == eLazyBoolYes; 172} 173 174bool ValueObjectPrinter::IsNil() { 175 if (m_is_nil == eLazyBoolCalculate) 176 m_is_nil = m_valobj->IsNilReference() ? eLazyBoolYes : eLazyBoolNo; 177 return m_is_nil == eLazyBoolYes; 178} 179 180bool ValueObjectPrinter::IsUninitialized() { 181 if (m_is_uninit == eLazyBoolCalculate) 182 m_is_uninit = 183 m_valobj->IsUninitializedReference() ? eLazyBoolYes : eLazyBoolNo; 184 return m_is_uninit == eLazyBoolYes; 185} 186 187bool ValueObjectPrinter::IsPtr() { 188 if (m_is_ptr == eLazyBoolCalculate) 189 m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; 190 return m_is_ptr == eLazyBoolYes; 191} 192 193bool ValueObjectPrinter::IsRef() { 194 if (m_is_ref == eLazyBoolCalculate) 195 m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; 196 return m_is_ref == eLazyBoolYes; 197} 198 199bool ValueObjectPrinter::IsAggregate() { 200 if (m_is_aggregate == eLazyBoolCalculate) 201 m_is_aggregate = 202 m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo; 203 return m_is_aggregate == eLazyBoolYes; 204} 205 206bool ValueObjectPrinter::IsInstancePointer() { 207 // you need to do this check on the value's clang type 208 if (m_is_instance_ptr == eLazyBoolCalculate) 209 m_is_instance_ptr = (m_valobj->GetValue().GetCompilerType().GetTypeInfo() & 210 eTypeInstanceIsPointer) != 0 211 ? eLazyBoolYes 212 : eLazyBoolNo; 213 if ((eLazyBoolYes == m_is_instance_ptr) && m_valobj->IsBaseClass()) 214 m_is_instance_ptr = eLazyBoolNo; 215 return m_is_instance_ptr == eLazyBoolYes; 216} 217 218bool ValueObjectPrinter::PrintLocationIfNeeded() { 219 if (m_options.m_show_location) { 220 m_stream->Printf("%s: ", m_valobj->GetLocationAsCString()); 221 return true; 222 } 223 return false; 224} 225 226void ValueObjectPrinter::PrintDecl() { 227 bool show_type = true; 228 // if we are at the root-level and been asked to hide the root's type, then 229 // hide it 230 if (m_curr_depth == 0 && m_options.m_hide_root_type) 231 show_type = false; 232 else 233 // otherwise decide according to the usual rules (asked to show types - 234 // always at the root level) 235 show_type = m_options.m_show_types || 236 (m_curr_depth == 0 && !m_options.m_flat_output); 237 238 StreamString typeName; 239 240 // always show the type at the root level if it is invalid 241 if (show_type) { 242 // Some ValueObjects don't have types (like registers sets). Only print the 243 // type if there is one to print 244 ConstString type_name; 245 if (m_compiler_type.IsValid()) { 246 if (m_options.m_use_type_display_name) 247 type_name = m_valobj->GetDisplayTypeName(); 248 else 249 type_name = m_valobj->GetQualifiedTypeName(); 250 } else { 251 // only show an invalid type name if the user explicitly triggered 252 // show_type 253 if (m_options.m_show_types) 254 type_name = ConstString("<invalid type>"); 255 else 256 type_name.Clear(); 257 } 258 259 if (type_name) { 260 std::string type_name_str(type_name.GetCString()); 261 if (m_options.m_hide_pointer_value) { 262 for (auto iter = type_name_str.find(" *"); iter != std::string::npos; 263 iter = type_name_str.find(" *")) { 264 type_name_str.erase(iter, 2); 265 } 266 } 267 typeName.Printf("%s", type_name_str.c_str()); 268 } 269 } 270 271 StreamString varName; 272 273 if (m_options.m_flat_output) { 274 // If we are showing types, also qualify the C++ base classes 275 const bool qualify_cxx_base_classes = show_type; 276 if (!m_options.m_hide_name) { 277 m_valobj->GetExpressionPath(varName, qualify_cxx_base_classes); 278 } 279 } else if (!m_options.m_hide_name) { 280 const char *name_cstr = GetRootNameForDisplay(""); 281 varName.Printf("%s", name_cstr); 282 } 283 284 bool decl_printed = false; 285 if (!m_options.m_decl_printing_helper) { 286 // if the user didn't give us a custom helper, pick one based upon the 287 // language, either the one that this printer is bound to, or the preferred 288 // one for the ValueObject 289 lldb::LanguageType lang_type = 290 (m_options.m_varformat_language == lldb::eLanguageTypeUnknown) 291 ? m_valobj->GetPreferredDisplayLanguage() 292 : m_options.m_varformat_language; 293 if (Language *lang_plugin = Language::FindPlugin(lang_type)) { 294 m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper(); 295 } 296 } 297 298 if (m_options.m_decl_printing_helper) { 299 ConstString type_name_cstr(typeName.GetString()); 300 ConstString var_name_cstr(varName.GetString()); 301 302 StreamString dest_stream; 303 if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr, 304 m_options, dest_stream)) { 305 decl_printed = true; 306 m_stream->PutCString(dest_stream.GetString()); 307 } 308 } 309 310 // if the helper failed, or there is none, do a default thing 311 if (!decl_printed) { 312 if (!typeName.Empty()) 313 m_stream->Printf("(%s) ", typeName.GetData()); 314 if (!varName.Empty()) 315 m_stream->Printf("%s =", varName.GetData()); 316 else if (!m_options.m_hide_name) 317 m_stream->Printf(" ="); 318 } 319} 320 321bool ValueObjectPrinter::CheckScopeIfNeeded() { 322 if (m_options.m_scope_already_checked) 323 return true; 324 return m_valobj->IsInScope(); 325} 326 327TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) { 328 if (!m_summary_formatter.second) { 329 TypeSummaryImpl *entry = m_options.m_summary_sp 330 ? m_options.m_summary_sp.get() 331 : m_valobj->GetSummaryFormat().get(); 332 333 if (m_options.m_omit_summary_depth > 0) 334 entry = nullptr; 335 m_summary_formatter.first = entry; 336 m_summary_formatter.second = true; 337 } 338 if (m_options.m_omit_summary_depth > 0 && null_if_omitted) 339 return nullptr; 340 return m_summary_formatter.first; 341} 342 343static bool IsPointerValue(const CompilerType &type) { 344 Flags type_flags(type.GetTypeInfo()); 345 if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer)) 346 return type_flags.AllClear(eTypeIsBuiltIn); 347 return false; 348} 349 350void ValueObjectPrinter::GetValueSummaryError(std::string &value, 351 std::string &summary, 352 std::string &error) { 353 lldb::Format format = m_options.m_format; 354 // if I am printing synthetized elements, apply the format to those elements 355 // only 356 if (m_options.m_pointer_as_array) 357 m_valobj->GetValueAsCString(lldb::eFormatDefault, value); 358 else if (format != eFormatDefault && format != m_valobj->GetFormat()) 359 m_valobj->GetValueAsCString(format, value); 360 else { 361 const char *val_cstr = m_valobj->GetValueAsCString(); 362 if (val_cstr) 363 value.assign(val_cstr); 364 } 365 const char *err_cstr = m_valobj->GetError().AsCString(); 366 if (err_cstr) 367 error.assign(err_cstr); 368 369 if (ShouldPrintValueObject()) { 370 if (IsNil()) 371 summary.assign("nil"); 372 else if (IsUninitialized()) 373 summary.assign("<uninitialized>"); 374 else if (m_options.m_omit_summary_depth == 0) { 375 TypeSummaryImpl *entry = GetSummaryFormatter(); 376 if (entry) 377 m_valobj->GetSummaryAsCString(entry, summary, 378 m_options.m_varformat_language); 379 else { 380 const char *sum_cstr = 381 m_valobj->GetSummaryAsCString(m_options.m_varformat_language); 382 if (sum_cstr) 383 summary.assign(sum_cstr); 384 } 385 } 386 } 387} 388 389bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, 390 bool &summary_printed) { 391 bool error_printed = false; 392 if (ShouldPrintValueObject()) { 393 if (!CheckScopeIfNeeded()) 394 m_error.assign("out of scope"); 395 if (m_error.empty()) { 396 GetValueSummaryError(m_value, m_summary, m_error); 397 } 398 if (m_error.size()) { 399 // we need to support scenarios in which it is actually fine for a value 400 // to have no type but - on the other hand - if we get an error *AND* 401 // have no type, we try to get out gracefully, since most often that 402 // combination means "could not resolve a type" and the default failure 403 // mode is quite ugly 404 if (!m_compiler_type.IsValid()) { 405 m_stream->Printf(" <could not resolve type>"); 406 return false; 407 } 408 409 error_printed = true; 410 m_stream->Printf(" <%s>\n", m_error.c_str()); 411 } else { 412 // Make sure we have a value and make sure the summary didn't specify 413 // that the value should not be printed - and do not print the value if 414 // this thing is nil (but show the value if the user passes a format 415 // explicitly) 416 TypeSummaryImpl *entry = GetSummaryFormatter(); 417 if (!IsNil() && !IsUninitialized() && !m_value.empty() && 418 (entry == nullptr || 419 (entry->DoesPrintValue(m_valobj) || 420 m_options.m_format != eFormatDefault) || 421 m_summary.empty()) && 422 !m_options.m_hide_value) { 423 if (m_options.m_hide_pointer_value && 424 IsPointerValue(m_valobj->GetCompilerType())) { 425 } else { 426 m_stream->Printf(" %s", m_value.c_str()); 427 value_printed = true; 428 } 429 } 430 431 if (m_summary.size()) { 432 m_stream->Printf(" %s", m_summary.c_str()); 433 summary_printed = true; 434 } 435 } 436 } 437 return !error_printed; 438} 439 440bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed, 441 bool summary_printed) { 442 if (ShouldPrintValueObject()) { 443 // let's avoid the overly verbose no description error for a nil thing 444 if (m_options.m_use_objc && !IsNil() && !IsUninitialized() && 445 (!m_options.m_pointer_as_array)) { 446 if (!m_options.m_hide_value || !m_options.m_hide_name) 447 m_stream->Printf(" "); 448 const char *object_desc = nullptr; 449 if (value_printed || summary_printed) 450 object_desc = m_valobj->GetObjectDescription(); 451 else 452 object_desc = GetDescriptionForDisplay(); 453 if (object_desc && *object_desc) { 454 // If the description already ends with a \n don't add another one. 455 size_t object_end = strlen(object_desc) - 1; 456 if (object_desc[object_end] == '\n') 457 m_stream->Printf("%s", object_desc); 458 else 459 m_stream->Printf("%s\n", object_desc); 460 return true; 461 } else if (!value_printed && !summary_printed) 462 return true; 463 else 464 return false; 465 } 466 } 467 return true; 468} 469 470bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const { 471 switch (m_mode) { 472 case Mode::Always: 473 case Mode::Default: 474 return m_count > 0; 475 case Mode::Never: 476 return false; 477 } 478 return false; 479} 480 481bool ValueObjectPrinter::ShouldPrintChildren( 482 bool is_failed_description, 483 DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 484 const bool is_ref = IsRef(); 485 const bool is_ptr = IsPtr(); 486 const bool is_uninit = IsUninitialized(); 487 488 if (is_uninit) 489 return false; 490 491 // if the user has specified an element count, always print children as it is 492 // explicit user demand being honored 493 if (m_options.m_pointer_as_array) 494 return true; 495 496 TypeSummaryImpl *entry = GetSummaryFormatter(); 497 498 if (m_options.m_use_objc) 499 return false; 500 501 if (is_failed_description || m_curr_depth < m_options.m_max_depth) { 502 // We will show children for all concrete types. We won't show pointer 503 // contents unless a pointer depth has been specified. We won't reference 504 // contents unless the reference is the root object (depth of zero). 505 506 // Use a new temporary pointer depth in case we override the current 507 // pointer depth below... 508 509 if (is_ptr || is_ref) { 510 // We have a pointer or reference whose value is an address. Make sure 511 // that address is not NULL 512 AddressType ptr_address_type; 513 if (m_valobj->GetPointerValue(&ptr_address_type) == 0) 514 return false; 515 516 const bool is_root_level = m_curr_depth == 0; 517 518 if (is_ref && is_root_level) { 519 // If this is the root object (depth is zero) that we are showing and 520 // it is a reference, and no pointer depth has been supplied print out 521 // what it references. Don't do this at deeper depths otherwise we can 522 // end up with infinite recursion... 523 return true; 524 } 525 526 return curr_ptr_depth.CanAllowExpansion(); 527 } 528 529 return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty()); 530 } 531 return false; 532} 533 534bool ValueObjectPrinter::ShouldExpandEmptyAggregates() { 535 TypeSummaryImpl *entry = GetSummaryFormatter(); 536 537 if (!entry) 538 return true; 539 540 return entry->DoesPrintEmptyAggregates(); 541} 542 543ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() { 544 return m_valobj; 545} 546 547void ValueObjectPrinter::PrintChildrenPreamble() { 548 if (m_options.m_flat_output) { 549 if (ShouldPrintValueObject()) 550 m_stream->EOL(); 551 } else { 552 if (ShouldPrintValueObject()) 553 m_stream->PutCString(IsRef() ? ": {\n" : " {\n"); 554 m_stream->IndentMore(); 555 } 556} 557 558void ValueObjectPrinter::PrintChild( 559 ValueObjectSP child_sp, 560 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 561 const uint32_t consumed_depth = (!m_options.m_pointer_as_array) ? 1 : 0; 562 const bool does_consume_ptr_depth = 563 ((IsPtr() && !m_options.m_pointer_as_array) || IsRef()); 564 565 DumpValueObjectOptions child_options(m_options); 566 child_options.SetFormat(m_options.m_format) 567 .SetSummary() 568 .SetRootValueObjectName(); 569 child_options.SetScopeChecked(true) 570 .SetHideName(m_options.m_hide_name) 571 .SetHideValue(m_options.m_hide_value) 572 .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 573 ? child_options.m_omit_summary_depth - 574 consumed_depth 575 : 0) 576 .SetElementCount(0); 577 578 if (child_sp.get()) { 579 ValueObjectPrinter child_printer( 580 child_sp.get(), m_stream, child_options, 581 does_consume_ptr_depth ? --curr_ptr_depth : curr_ptr_depth, 582 m_curr_depth + consumed_depth, m_printed_instance_pointers); 583 child_printer.PrintValueObject(); 584 } 585} 586 587uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) { 588 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 589 590 if (m_options.m_pointer_as_array) 591 return m_options.m_pointer_as_array.m_element_count; 592 593 size_t num_children = synth_m_valobj->GetNumChildren(); 594 print_dotdotdot = false; 595 if (num_children) { 596 const size_t max_num_children = 597 m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); 598 599 if (num_children > max_num_children && !m_options.m_ignore_cap) { 600 print_dotdotdot = true; 601 return max_num_children; 602 } 603 } 604 return num_children; 605} 606 607void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) { 608 if (!m_options.m_flat_output) { 609 if (print_dotdotdot) { 610 m_valobj->GetTargetSP() 611 ->GetDebugger() 612 .GetCommandInterpreter() 613 .ChildrenTruncated(); 614 m_stream->Indent("...\n"); 615 } 616 m_stream->IndentLess(); 617 m_stream->Indent("}\n"); 618 } 619} 620 621bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed, 622 bool summary_printed) { 623 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 624 625 if (!IsAggregate()) 626 return false; 627 628 if (!m_options.m_reveal_empty_aggregates) { 629 if (value_printed || summary_printed) 630 return false; 631 } 632 633 if (synth_m_valobj->MightHaveChildren()) 634 return true; 635 636 if (m_val_summary_ok) 637 return false; 638 639 return true; 640} 641 642static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride, 643 size_t logical) { 644 return base + logical * stride; 645} 646 647ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject *synth_valobj, 648 size_t idx) { 649 if (m_options.m_pointer_as_array) { 650 // if generating pointer-as-array children, use GetSyntheticArrayMember 651 return synth_valobj->GetSyntheticArrayMember( 652 PhysicalIndexForLogicalIndex( 653 m_options.m_pointer_as_array.m_base_element, 654 m_options.m_pointer_as_array.m_stride, idx), 655 true); 656 } else { 657 // otherwise, do the usual thing 658 return synth_valobj->GetChildAtIndex(idx, true); 659 } 660} 661 662void ValueObjectPrinter::PrintChildren( 663 bool value_printed, bool summary_printed, 664 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 665 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 666 667 bool print_dotdotdot = false; 668 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 669 if (num_children) { 670 bool any_children_printed = false; 671 672 for (size_t idx = 0; idx < num_children; ++idx) { 673 if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) { 674 if (!any_children_printed) { 675 PrintChildrenPreamble(); 676 any_children_printed = true; 677 } 678 PrintChild(child_sp, curr_ptr_depth); 679 } 680 } 681 682 if (any_children_printed) 683 PrintChildrenPostamble(print_dotdotdot); 684 else { 685 if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 686 if (ShouldPrintValueObject()) 687 m_stream->PutCString(" {}\n"); 688 else 689 m_stream->EOL(); 690 } else 691 m_stream->EOL(); 692 } 693 } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 694 // Aggregate, no children... 695 if (ShouldPrintValueObject()) { 696 // if it has a synthetic value, then don't print {}, the synthetic 697 // children are probably only being used to vend a value 698 if (m_valobj->DoesProvideSyntheticValue() || 699 !ShouldExpandEmptyAggregates()) 700 m_stream->PutCString("\n"); 701 else 702 m_stream->PutCString(" {}\n"); 703 } 704 } else { 705 if (ShouldPrintValueObject()) 706 m_stream->EOL(); 707 } 708} 709 710bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) { 711 if (!GetMostSpecializedValue() || m_valobj == nullptr) 712 return false; 713 714 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 715 716 bool print_dotdotdot = false; 717 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 718 719 if (num_children) { 720 m_stream->PutChar('('); 721 722 for (uint32_t idx = 0; idx < num_children; ++idx) { 723 lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true)); 724 if (child_sp) 725 child_sp = child_sp->GetQualifiedRepresentationIfAvailable( 726 m_options.m_use_dynamic, m_options.m_use_synthetic); 727 if (child_sp) { 728 if (idx) 729 m_stream->PutCString(", "); 730 if (!hide_names) { 731 const char *name = child_sp.get()->GetName().AsCString(); 732 if (name && *name) { 733 m_stream->PutCString(name); 734 m_stream->PutCString(" = "); 735 } 736 } 737 child_sp->DumpPrintableRepresentation( 738 *m_stream, ValueObject::eValueObjectRepresentationStyleSummary, 739 m_options.m_format, 740 ValueObject::PrintableRepresentationSpecialCases::eDisable); 741 } 742 } 743 744 if (print_dotdotdot) 745 m_stream->PutCString(", ...)"); 746 else 747 m_stream->PutChar(')'); 748 } 749 return true; 750} 751 752void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, 753 bool summary_printed) { 754 // this flag controls whether we tried to display a description for this 755 // object and failed if that happens, we want to display the children, if any 756 bool is_failed_description = 757 !PrintObjectDescriptionIfNeeded(value_printed, summary_printed); 758 759 auto curr_ptr_depth = m_ptr_depth; 760 bool print_children = 761 ShouldPrintChildren(is_failed_description, curr_ptr_depth); 762 bool print_oneline = 763 (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types || 764 !m_options.m_allow_oneliner_mode || m_options.m_flat_output || 765 (m_options.m_pointer_as_array) || m_options.m_show_location) 766 ? false 767 : DataVisualization::ShouldPrintAsOneLiner(*m_valobj); 768 bool is_instance_ptr = IsInstancePointer(); 769 uint64_t instance_ptr_value = LLDB_INVALID_ADDRESS; 770 771 if (print_children && is_instance_ptr) { 772 instance_ptr_value = m_valobj->GetValueAsUnsigned(0); 773 if (m_printed_instance_pointers->count(instance_ptr_value)) { 774 // we already printed this instance-is-pointer thing, so don't expand it 775 m_stream->PutCString(" {...}\n"); 776 777 // we're done here - get out fast 778 return; 779 } else 780 m_printed_instance_pointers->emplace( 781 instance_ptr_value); // remember this guy for future reference 782 } 783 784 if (print_children) { 785 if (print_oneline) { 786 m_stream->PutChar(' '); 787 PrintChildrenOneLiner(false); 788 m_stream->EOL(); 789 } else 790 PrintChildren(value_printed, summary_printed, curr_ptr_depth); 791 } else if (m_curr_depth >= m_options.m_max_depth && IsAggregate() && 792 ShouldPrintValueObject()) { 793 m_stream->PutCString("{...}\n"); 794 } else 795 m_stream->EOL(); 796} 797 798bool ValueObjectPrinter::ShouldPrintValidation() { 799 return m_options.m_run_validator; 800} 801 802bool ValueObjectPrinter::PrintValidationMarkerIfNeeded() { 803 if (!ShouldPrintValidation()) 804 return false; 805 806 m_validation = m_valobj->GetValidationStatus(); 807 808 if (TypeValidatorResult::Failure == m_validation.first) { 809 m_stream->Printf("! "); 810 return true; 811 } 812 813 return false; 814} 815 816bool ValueObjectPrinter::PrintValidationErrorIfNeeded() { 817 if (!ShouldPrintValidation()) 818 return false; 819 820 if (TypeValidatorResult::Success == m_validation.first) 821 return false; 822 823 if (m_validation.second.empty()) 824 m_validation.second.assign("unknown error"); 825 826 m_stream->Printf(" ! validation error: %s", m_validation.second.c_str()); 827 m_stream->EOL(); 828 829 return true; 830} 831