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