LLDB  mainline
ValueObjectPrinter.cpp
Go to the documentation of this file.
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 
10 
11 #include "lldb/Core/ValueObject.h"
14 #include "lldb/Target/Language.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Utility/Stream.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
21 ValueObjectPrinter::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 
31 ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s,
32  const DumpValueObjectOptions &options) {
33  Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);
34 }
35 
36 ValueObjectPrinter::ValueObjectPrinter(
37  ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options,
38  const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,
39  InstancePointersSetSP printed_instance_pointers) {
40  Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers);
41 }
42 
43 void ValueObjectPrinter::Init(
44  ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options,
45  const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,
46  InstancePointersSetSP printed_instance_pointers) {
47  m_orig_valobj = valobj;
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
71 }
72 
73 bool 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 
102 bool 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 
149 const 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 
158 const 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 
165 bool 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 
174 bool 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 
180 bool 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 
187 bool 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 
193 bool 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 
199 bool 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 
206 bool 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 
218 bool 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 
226 void 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 
321 bool ValueObjectPrinter::CheckScopeIfNeeded() {
322  if (m_options.m_scope_already_checked)
323  return true;
324  return m_valobj->IsInScope();
325 }
326 
327 TypeSummaryImpl *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 = NULL;
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 
343 static 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 
350 void 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 
389 bool 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 == NULL || (entry->DoesPrintValue(m_valobj) ||
419  m_options.m_format != eFormatDefault) ||
420  m_summary.empty()) &&
421  !m_options.m_hide_value) {
422  if (m_options.m_hide_pointer_value &&
423  IsPointerValue(m_valobj->GetCompilerType())) {
424  } else {
425  m_stream->Printf(" %s", m_value.c_str());
426  value_printed = true;
427  }
428  }
429 
430  if (m_summary.size()) {
431  m_stream->Printf(" %s", m_summary.c_str());
432  summary_printed = true;
433  }
434  }
435  }
436  return !error_printed;
437 }
438 
439 bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
440  bool summary_printed) {
441  if (ShouldPrintValueObject()) {
442  // let's avoid the overly verbose no description error for a nil thing
443  if (m_options.m_use_objc && !IsNil() && !IsUninitialized() &&
444  (!m_options.m_pointer_as_array)) {
445  if (!m_options.m_hide_value || !m_options.m_hide_name)
446  m_stream->Printf(" ");
447  const char *object_desc = nullptr;
448  if (value_printed || summary_printed)
449  object_desc = m_valobj->GetObjectDescription();
450  else
451  object_desc = GetDescriptionForDisplay();
452  if (object_desc && *object_desc) {
453  // If the description already ends with a \n don't add another one.
454  size_t object_end = strlen(object_desc) - 1;
455  if (object_desc[object_end] == '\n')
456  m_stream->Printf("%s", object_desc);
457  else
458  m_stream->Printf("%s\n", object_desc);
459  return true;
460  } else if (!value_printed && !summary_printed)
461  return true;
462  else
463  return false;
464  }
465  }
466  return true;
467 }
468 
469 bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
470  switch (m_mode) {
471  case Mode::Always:
472  case Mode::Default:
473  return m_count > 0;
474  case Mode::Never:
475  return false;
476  }
477  return false;
478 }
479 
480 bool ValueObjectPrinter::ShouldPrintChildren(
481  bool is_failed_description,
482  DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
483  const bool is_ref = IsRef();
484  const bool is_ptr = IsPtr();
485  const bool is_uninit = IsUninitialized();
486 
487  if (is_uninit)
488  return false;
489 
490  // if the user has specified an element count, always print children as it is
491  // explicit user demand being honored
492  if (m_options.m_pointer_as_array)
493  return true;
494 
495  TypeSummaryImpl *entry = GetSummaryFormatter();
496 
497  if (m_options.m_use_objc)
498  return false;
499 
500  if (is_failed_description || m_curr_depth < m_options.m_max_depth) {
501  // We will show children for all concrete types. We won't show pointer
502  // contents unless a pointer depth has been specified. We won't reference
503  // contents unless the reference is the root object (depth of zero).
504 
505  // Use a new temporary pointer depth in case we override the current
506  // pointer depth below...
507 
508  if (is_ptr || is_ref) {
509  // We have a pointer or reference whose value is an address. Make sure
510  // that address is not NULL
511  AddressType ptr_address_type;
512  if (m_valobj->GetPointerValue(&ptr_address_type) == 0)
513  return false;
514 
515  const bool is_root_level = m_curr_depth == 0;
516 
517  if (is_ref && is_root_level) {
518  // If this is the root object (depth is zero) that we are showing and
519  // it is a reference, and no pointer depth has been supplied print out
520  // what it references. Don't do this at deeper depths otherwise we can
521  // end up with infinite recursion...
522  return true;
523  }
524 
525  return curr_ptr_depth.CanAllowExpansion();
526  }
527 
528  return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty());
529  }
530  return false;
531 }
532 
533 bool ValueObjectPrinter::ShouldExpandEmptyAggregates() {
534  TypeSummaryImpl *entry = GetSummaryFormatter();
535 
536  if (!entry)
537  return true;
538 
539  return entry->DoesPrintEmptyAggregates();
540 }
541 
542 ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() {
543  return m_valobj;
544 }
545 
546 void ValueObjectPrinter::PrintChildrenPreamble() {
547  if (m_options.m_flat_output) {
548  if (ShouldPrintValueObject())
549  m_stream->EOL();
550  } else {
551  if (ShouldPrintValueObject())
552  m_stream->PutCString(IsRef() ? ": {\n" : " {\n");
553  m_stream->IndentMore();
554  }
555 }
556 
557 void ValueObjectPrinter::PrintChild(
558  ValueObjectSP child_sp,
559  const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
560  const uint32_t consumed_depth = (!m_options.m_pointer_as_array) ? 1 : 0;
561  const bool does_consume_ptr_depth =
562  ((IsPtr() && !m_options.m_pointer_as_array) || IsRef());
563 
564  DumpValueObjectOptions child_options(m_options);
565  child_options.SetFormat(m_options.m_format)
566  .SetSummary()
568  child_options.SetScopeChecked(true)
569  .SetHideName(m_options.m_hide_name)
570  .SetHideValue(m_options.m_hide_value)
571  .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1
572  ? child_options.m_omit_summary_depth -
573  consumed_depth
574  : 0)
575  .SetElementCount(0);
576 
577  if (child_sp.get()) {
578  ValueObjectPrinter child_printer(
579  child_sp.get(), m_stream, child_options,
580  does_consume_ptr_depth ? --curr_ptr_depth : curr_ptr_depth,
581  m_curr_depth + consumed_depth, m_printed_instance_pointers);
582  child_printer.PrintValueObject();
583  }
584 }
585 
586 uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) {
587  ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
588 
589  if (m_options.m_pointer_as_array)
590  return m_options.m_pointer_as_array.m_element_count;
591 
592  size_t num_children = synth_m_valobj->GetNumChildren();
593  print_dotdotdot = false;
594  if (num_children) {
595  const size_t max_num_children =
596  m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
597 
598  if (num_children > max_num_children && !m_options.m_ignore_cap) {
599  print_dotdotdot = true;
600  return max_num_children;
601  }
602  }
603  return num_children;
604 }
605 
606 void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) {
607  if (!m_options.m_flat_output) {
608  if (print_dotdotdot) {
609  m_valobj->GetTargetSP()
610  ->GetDebugger()
611  .GetCommandInterpreter()
612  .ChildrenTruncated();
613  m_stream->Indent("...\n");
614  }
615  m_stream->IndentLess();
616  m_stream->Indent("}\n");
617  }
618 }
619 
620 bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed,
621  bool summary_printed) {
622  ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
623 
624  if (!IsAggregate())
625  return false;
626 
627  if (!m_options.m_reveal_empty_aggregates) {
628  if (value_printed || summary_printed)
629  return false;
630  }
631 
632  if (synth_m_valobj->MightHaveChildren())
633  return true;
634 
635  if (m_val_summary_ok)
636  return false;
637 
638  return true;
639 }
640 
641 static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride,
642  size_t logical) {
643  return base + logical * stride;
644 }
645 
646 ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject *synth_valobj,
647  size_t idx) {
648  if (m_options.m_pointer_as_array) {
649  // if generating pointer-as-array children, use GetSyntheticArrayMember
650  return synth_valobj->GetSyntheticArrayMember(
652  m_options.m_pointer_as_array.m_base_element,
653  m_options.m_pointer_as_array.m_stride, idx),
654  true);
655  } else {
656  // otherwise, do the usual thing
657  return synth_valobj->GetChildAtIndex(idx, true);
658  }
659 }
660 
661 void ValueObjectPrinter::PrintChildren(
662  bool value_printed, bool summary_printed,
663  const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
664  ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
665 
666  bool print_dotdotdot = false;
667  size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
668  if (num_children) {
669  bool any_children_printed = false;
670 
671  for (size_t idx = 0; idx < num_children; ++idx) {
672  if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) {
673  if (!any_children_printed) {
674  PrintChildrenPreamble();
675  any_children_printed = true;
676  }
677  PrintChild(child_sp, curr_ptr_depth);
678  }
679  }
680 
681  if (any_children_printed)
682  PrintChildrenPostamble(print_dotdotdot);
683  else {
684  if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {
685  if (ShouldPrintValueObject())
686  m_stream->PutCString(" {}\n");
687  else
688  m_stream->EOL();
689  } else
690  m_stream->EOL();
691  }
692  } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {
693  // Aggregate, no children...
694  if (ShouldPrintValueObject()) {
695  // if it has a synthetic value, then don't print {}, the synthetic
696  // children are probably only being used to vend a value
697  if (m_valobj->DoesProvideSyntheticValue() ||
698  !ShouldExpandEmptyAggregates())
699  m_stream->PutCString("\n");
700  else
701  m_stream->PutCString(" {}\n");
702  }
703  } else {
704  if (ShouldPrintValueObject())
705  m_stream->EOL();
706  }
707 }
708 
709 bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
710  if (!GetMostSpecializedValue() || m_valobj == nullptr)
711  return false;
712 
713  ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
714 
715  bool print_dotdotdot = false;
716  size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
717 
718  if (num_children) {
719  m_stream->PutChar('(');
720 
721  for (uint32_t idx = 0; idx < num_children; ++idx) {
722  lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true));
723  if (child_sp)
724  child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
725  m_options.m_use_dynamic, m_options.m_use_synthetic);
726  if (child_sp) {
727  if (idx)
728  m_stream->PutCString(", ");
729  if (!hide_names) {
730  const char *name = child_sp.get()->GetName().AsCString();
731  if (name && *name) {
732  m_stream->PutCString(name);
733  m_stream->PutCString(" = ");
734  }
735  }
736  child_sp->DumpPrintableRepresentation(
737  *m_stream, ValueObject::eValueObjectRepresentationStyleSummary,
738  m_options.m_format,
739  ValueObject::PrintableRepresentationSpecialCases::eDisable);
740  }
741  }
742 
743  if (print_dotdotdot)
744  m_stream->PutCString(", ...)");
745  else
746  m_stream->PutChar(')');
747  }
748  return true;
749 }
750 
751 void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
752  bool summary_printed) {
753  // this flag controls whether we tried to display a description for this
754  // object and failed if that happens, we want to display the children, if any
755  bool is_failed_description =
756  !PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
757 
758  auto curr_ptr_depth = m_ptr_depth;
759  bool print_children =
760  ShouldPrintChildren(is_failed_description, curr_ptr_depth);
761  bool print_oneline =
762  (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types ||
763  !m_options.m_allow_oneliner_mode || m_options.m_flat_output ||
764  (m_options.m_pointer_as_array) || m_options.m_show_location)
765  ? false
766  : DataVisualization::ShouldPrintAsOneLiner(*m_valobj);
767  bool is_instance_ptr = IsInstancePointer();
768  uint64_t instance_ptr_value = LLDB_INVALID_ADDRESS;
769 
770  if (print_children && is_instance_ptr) {
771  instance_ptr_value = m_valobj->GetValueAsUnsigned(0);
772  if (m_printed_instance_pointers->count(instance_ptr_value)) {
773  // we already printed this instance-is-pointer thing, so don't expand it
774  m_stream->PutCString(" {...}\n");
775 
776  // we're done here - get out fast
777  return;
778  } else
779  m_printed_instance_pointers->emplace(
780  instance_ptr_value); // remember this guy for future reference
781  }
782 
783  if (print_children) {
784  if (print_oneline) {
785  m_stream->PutChar(' ');
786  PrintChildrenOneLiner(false);
787  m_stream->EOL();
788  } else
789  PrintChildren(value_printed, summary_printed, curr_ptr_depth);
790  } else if (m_curr_depth >= m_options.m_max_depth && IsAggregate() &&
791  ShouldPrintValueObject()) {
792  m_stream->PutCString("{...}\n");
793  } else
794  m_stream->EOL();
795 }
796 
797 bool ValueObjectPrinter::ShouldPrintValidation() {
798  return m_options.m_run_validator;
799 }
800 
801 bool ValueObjectPrinter::PrintValidationMarkerIfNeeded() {
802  if (!ShouldPrintValidation())
803  return false;
804 
805  m_validation = m_valobj->GetValidationStatus();
806 
807  if (TypeValidatorResult::Failure == m_validation.first) {
808  m_stream->Printf("! ");
809  return true;
810  }
811 
812  return false;
813 }
814 
815 bool ValueObjectPrinter::PrintValidationErrorIfNeeded() {
816  if (!ShouldPrintValidation())
817  return false;
818 
819  if (TypeValidatorResult::Success == m_validation.first)
820  return false;
821 
822  if (m_validation.second.empty())
823  m_validation.second.assign("unknown error");
824 
825  m_stream->Printf(" ! validation error: %s", m_validation.second.c_str());
826  m_stream->EOL();
827 
828  return true;
829 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
virtual bool DoesPrintEmptyAggregates() const
Definition: TypeSummary.h:217
CompilerType GetCompilerType()
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
DumpValueObjectOptions & SetHideValue(bool hide_value=false)
DumpValueObjectOptions & SetSummary(lldb::TypeSummaryImplSP summary=lldb::TypeSummaryImplSP())
virtual bool DoesPrintValue(ValueObject *valobj) const
Definition: TypeSummary.h:221
DumpValueObjectOptions & SetHideName(bool hide_name=false)
std::shared_ptr< InstancePointersSet > InstancePointersSetSP
DumpValueObjectOptions & SetElementCount(uint32_t element_count=0)
lldb::ValueObjectSP GetSyntheticValue(bool use_synthetic=true)
uint32_t GetTypeInfo(CompilerType *pointee_or_element_compiler_type=nullptr) const
DumpValueObjectOptions & SetScopeChecked(bool check=true)
static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride, size_t logical)
const char * GetData() const
Definition: StreamString.h:43
DumpValueObjectOptions & SetRootValueObjectName(const char *name=nullptr)
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
LanguageType
Programming language type.
std::set< uint64_t > InstancePointersSet
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
virtual lldb::ValueObjectSP GetDynamicValue(lldb::DynamicValueType valueType)
A class to manage flags.
Definition: Flags.h:22
virtual lldb::ValueObjectSP GetStaticValue()
A uniqued constant string class.
Definition: ConstString.h:38
Unknown or invalid language value.
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:247
Definition: SBAddress.h:15
virtual bool MightHaveChildren()
Find out if a ValueObject might have children.
size_t GetNumChildren(uint32_t max=UINT32_MAX)
virtual bool DoesPrintChildren(ValueObject *valobj) const
Definition: TypeSummary.h:213
bool AllClear(ValueType mask) const
Test if all bits in mask are clear.
Definition: Flags.h:114
lldb::ValueObjectSP GetSyntheticArrayMember(size_t index, bool can_create)
DumpValueObjectOptions & SetFormat(lldb::Format format=lldb::eFormatDefault)
DumpValueObjectOptions & SetOmitSummaryDepth(uint32_t depth=0)
virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
void Clear()
Clear this object&#39;s state.
Definition: ConstString.h:263
static bool IsPointerValue(const CompilerType &type)