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