1dda28197Spatrick //===-- ValueObjectPrinter.cpp --------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/DataFormatters/ValueObjectPrinter.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/ValueObject.h"
12061da546Spatrick #include "lldb/DataFormatters/DataVisualization.h"
13061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
14061da546Spatrick #include "lldb/Target/Language.h"
15061da546Spatrick #include "lldb/Target/Target.h"
16061da546Spatrick #include "lldb/Utility/Stream.h"
17061da546Spatrick
18061da546Spatrick using namespace lldb;
19061da546Spatrick using namespace lldb_private;
20061da546Spatrick
ValueObjectPrinter(ValueObject * valobj,Stream * s)21061da546Spatrick ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s) {
22061da546Spatrick if (valobj) {
23061da546Spatrick DumpValueObjectOptions options(*valobj);
24061da546Spatrick Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);
25061da546Spatrick } else {
26061da546Spatrick DumpValueObjectOptions options;
27061da546Spatrick Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);
28061da546Spatrick }
29061da546Spatrick }
30061da546Spatrick
ValueObjectPrinter(ValueObject * valobj,Stream * s,const DumpValueObjectOptions & options)31061da546Spatrick ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s,
32061da546Spatrick const DumpValueObjectOptions &options) {
33061da546Spatrick Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);
34061da546Spatrick }
35061da546Spatrick
ValueObjectPrinter(ValueObject * valobj,Stream * s,const DumpValueObjectOptions & options,const DumpValueObjectOptions::PointerDepth & ptr_depth,uint32_t curr_depth,InstancePointersSetSP printed_instance_pointers)36061da546Spatrick ValueObjectPrinter::ValueObjectPrinter(
37061da546Spatrick ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options,
38061da546Spatrick const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,
39061da546Spatrick InstancePointersSetSP printed_instance_pointers) {
40061da546Spatrick Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers);
41061da546Spatrick }
42061da546Spatrick
Init(ValueObject * valobj,Stream * s,const DumpValueObjectOptions & options,const DumpValueObjectOptions::PointerDepth & ptr_depth,uint32_t curr_depth,InstancePointersSetSP printed_instance_pointers)43061da546Spatrick void ValueObjectPrinter::Init(
44061da546Spatrick ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options,
45061da546Spatrick const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,
46061da546Spatrick InstancePointersSetSP printed_instance_pointers) {
47061da546Spatrick m_orig_valobj = valobj;
48061da546Spatrick m_valobj = nullptr;
49061da546Spatrick m_stream = s;
50061da546Spatrick m_options = options;
51061da546Spatrick m_ptr_depth = ptr_depth;
52061da546Spatrick m_curr_depth = curr_depth;
53061da546Spatrick assert(m_orig_valobj && "cannot print a NULL ValueObject");
54061da546Spatrick assert(m_stream && "cannot print to a NULL Stream");
55061da546Spatrick m_should_print = eLazyBoolCalculate;
56061da546Spatrick m_is_nil = eLazyBoolCalculate;
57061da546Spatrick m_is_uninit = eLazyBoolCalculate;
58061da546Spatrick m_is_ptr = eLazyBoolCalculate;
59061da546Spatrick m_is_ref = eLazyBoolCalculate;
60061da546Spatrick m_is_aggregate = eLazyBoolCalculate;
61061da546Spatrick m_is_instance_ptr = eLazyBoolCalculate;
62061da546Spatrick m_summary_formatter = {nullptr, false};
63061da546Spatrick m_value.assign("");
64061da546Spatrick m_summary.assign("");
65061da546Spatrick m_error.assign("");
66061da546Spatrick m_val_summary_ok = false;
67061da546Spatrick m_printed_instance_pointers =
68061da546Spatrick printed_instance_pointers
69061da546Spatrick ? printed_instance_pointers
70061da546Spatrick : InstancePointersSetSP(new InstancePointersSet());
71061da546Spatrick }
72061da546Spatrick
PrintValueObject()73061da546Spatrick bool ValueObjectPrinter::PrintValueObject() {
74061da546Spatrick if (!GetMostSpecializedValue() || m_valobj == nullptr)
75061da546Spatrick return false;
76061da546Spatrick
77061da546Spatrick if (ShouldPrintValueObject()) {
78061da546Spatrick PrintLocationIfNeeded();
79061da546Spatrick m_stream->Indent();
80061da546Spatrick
81061da546Spatrick PrintDecl();
82061da546Spatrick }
83061da546Spatrick
84061da546Spatrick bool value_printed = false;
85061da546Spatrick bool summary_printed = false;
86061da546Spatrick
87061da546Spatrick m_val_summary_ok =
88061da546Spatrick PrintValueAndSummaryIfNeeded(value_printed, summary_printed);
89061da546Spatrick
90061da546Spatrick if (m_val_summary_ok)
91061da546Spatrick PrintChildrenIfNeeded(value_printed, summary_printed);
92061da546Spatrick else
93061da546Spatrick m_stream->EOL();
94061da546Spatrick
95061da546Spatrick return true;
96061da546Spatrick }
97061da546Spatrick
GetMostSpecializedValue()98061da546Spatrick bool ValueObjectPrinter::GetMostSpecializedValue() {
99061da546Spatrick if (m_valobj)
100061da546Spatrick return true;
101061da546Spatrick bool update_success = m_orig_valobj->UpdateValueIfNeeded(true);
102061da546Spatrick if (!update_success) {
103061da546Spatrick m_valobj = m_orig_valobj;
104061da546Spatrick } else {
105061da546Spatrick if (m_orig_valobj->IsDynamic()) {
106061da546Spatrick if (m_options.m_use_dynamic == eNoDynamicValues) {
107061da546Spatrick ValueObject *static_value = m_orig_valobj->GetStaticValue().get();
108061da546Spatrick if (static_value)
109061da546Spatrick m_valobj = static_value;
110061da546Spatrick else
111061da546Spatrick m_valobj = m_orig_valobj;
112061da546Spatrick } else
113061da546Spatrick m_valobj = m_orig_valobj;
114061da546Spatrick } else {
115061da546Spatrick if (m_options.m_use_dynamic != eNoDynamicValues) {
116061da546Spatrick ValueObject *dynamic_value =
117061da546Spatrick m_orig_valobj->GetDynamicValue(m_options.m_use_dynamic).get();
118061da546Spatrick if (dynamic_value)
119061da546Spatrick m_valobj = dynamic_value;
120061da546Spatrick else
121061da546Spatrick m_valobj = m_orig_valobj;
122061da546Spatrick } else
123061da546Spatrick m_valobj = m_orig_valobj;
124061da546Spatrick }
125061da546Spatrick
126061da546Spatrick if (m_valobj->IsSynthetic()) {
127061da546Spatrick if (!m_options.m_use_synthetic) {
128061da546Spatrick ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get();
129061da546Spatrick if (non_synthetic)
130061da546Spatrick m_valobj = non_synthetic;
131061da546Spatrick }
132061da546Spatrick } else {
133061da546Spatrick if (m_options.m_use_synthetic) {
134061da546Spatrick ValueObject *synthetic = m_valobj->GetSyntheticValue().get();
135061da546Spatrick if (synthetic)
136061da546Spatrick m_valobj = synthetic;
137061da546Spatrick }
138061da546Spatrick }
139061da546Spatrick }
140061da546Spatrick m_compiler_type = m_valobj->GetCompilerType();
141061da546Spatrick m_type_flags = m_compiler_type.GetTypeInfo();
142061da546Spatrick return true;
143061da546Spatrick }
144061da546Spatrick
GetDescriptionForDisplay()145061da546Spatrick const char *ValueObjectPrinter::GetDescriptionForDisplay() {
146061da546Spatrick const char *str = m_valobj->GetObjectDescription();
147061da546Spatrick if (!str)
148061da546Spatrick str = m_valobj->GetSummaryAsCString();
149061da546Spatrick if (!str)
150061da546Spatrick str = m_valobj->GetValueAsCString();
151061da546Spatrick return str;
152061da546Spatrick }
153061da546Spatrick
GetRootNameForDisplay()154dda28197Spatrick const char *ValueObjectPrinter::GetRootNameForDisplay() {
155061da546Spatrick const char *root_valobj_name = m_options.m_root_valobj_name.empty()
156061da546Spatrick ? m_valobj->GetName().AsCString()
157061da546Spatrick : m_options.m_root_valobj_name.c_str();
158dda28197Spatrick return root_valobj_name ? root_valobj_name : "";
159061da546Spatrick }
160061da546Spatrick
ShouldPrintValueObject()161061da546Spatrick bool ValueObjectPrinter::ShouldPrintValueObject() {
162061da546Spatrick if (m_should_print == eLazyBoolCalculate)
163061da546Spatrick m_should_print =
164061da546Spatrick (!m_options.m_flat_output || m_type_flags.Test(eTypeHasValue))
165061da546Spatrick ? eLazyBoolYes
166061da546Spatrick : eLazyBoolNo;
167061da546Spatrick return m_should_print == eLazyBoolYes;
168061da546Spatrick }
169061da546Spatrick
IsNil()170061da546Spatrick bool ValueObjectPrinter::IsNil() {
171061da546Spatrick if (m_is_nil == eLazyBoolCalculate)
172061da546Spatrick m_is_nil = m_valobj->IsNilReference() ? eLazyBoolYes : eLazyBoolNo;
173061da546Spatrick return m_is_nil == eLazyBoolYes;
174061da546Spatrick }
175061da546Spatrick
IsUninitialized()176061da546Spatrick bool ValueObjectPrinter::IsUninitialized() {
177061da546Spatrick if (m_is_uninit == eLazyBoolCalculate)
178061da546Spatrick m_is_uninit =
179061da546Spatrick m_valobj->IsUninitializedReference() ? eLazyBoolYes : eLazyBoolNo;
180061da546Spatrick return m_is_uninit == eLazyBoolYes;
181061da546Spatrick }
182061da546Spatrick
IsPtr()183061da546Spatrick bool ValueObjectPrinter::IsPtr() {
184061da546Spatrick if (m_is_ptr == eLazyBoolCalculate)
185061da546Spatrick m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo;
186061da546Spatrick return m_is_ptr == eLazyBoolYes;
187061da546Spatrick }
188061da546Spatrick
IsRef()189061da546Spatrick bool ValueObjectPrinter::IsRef() {
190061da546Spatrick if (m_is_ref == eLazyBoolCalculate)
191061da546Spatrick m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo;
192061da546Spatrick return m_is_ref == eLazyBoolYes;
193061da546Spatrick }
194061da546Spatrick
IsAggregate()195061da546Spatrick bool ValueObjectPrinter::IsAggregate() {
196061da546Spatrick if (m_is_aggregate == eLazyBoolCalculate)
197061da546Spatrick m_is_aggregate =
198061da546Spatrick m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo;
199061da546Spatrick return m_is_aggregate == eLazyBoolYes;
200061da546Spatrick }
201061da546Spatrick
IsInstancePointer()202061da546Spatrick bool ValueObjectPrinter::IsInstancePointer() {
203061da546Spatrick // you need to do this check on the value's clang type
204061da546Spatrick if (m_is_instance_ptr == eLazyBoolCalculate)
205061da546Spatrick m_is_instance_ptr = (m_valobj->GetValue().GetCompilerType().GetTypeInfo() &
206061da546Spatrick eTypeInstanceIsPointer) != 0
207061da546Spatrick ? eLazyBoolYes
208061da546Spatrick : eLazyBoolNo;
209061da546Spatrick if ((eLazyBoolYes == m_is_instance_ptr) && m_valobj->IsBaseClass())
210061da546Spatrick m_is_instance_ptr = eLazyBoolNo;
211061da546Spatrick return m_is_instance_ptr == eLazyBoolYes;
212061da546Spatrick }
213061da546Spatrick
PrintLocationIfNeeded()214061da546Spatrick bool ValueObjectPrinter::PrintLocationIfNeeded() {
215061da546Spatrick if (m_options.m_show_location) {
216061da546Spatrick m_stream->Printf("%s: ", m_valobj->GetLocationAsCString());
217061da546Spatrick return true;
218061da546Spatrick }
219061da546Spatrick return false;
220061da546Spatrick }
221061da546Spatrick
PrintDecl()222061da546Spatrick void ValueObjectPrinter::PrintDecl() {
223061da546Spatrick bool show_type = true;
224061da546Spatrick // if we are at the root-level and been asked to hide the root's type, then
225061da546Spatrick // hide it
226061da546Spatrick if (m_curr_depth == 0 && m_options.m_hide_root_type)
227061da546Spatrick show_type = false;
228061da546Spatrick else
229061da546Spatrick // otherwise decide according to the usual rules (asked to show types -
230061da546Spatrick // always at the root level)
231061da546Spatrick show_type = m_options.m_show_types ||
232061da546Spatrick (m_curr_depth == 0 && !m_options.m_flat_output);
233061da546Spatrick
234061da546Spatrick StreamString typeName;
235061da546Spatrick
236061da546Spatrick // always show the type at the root level if it is invalid
237061da546Spatrick if (show_type) {
238061da546Spatrick // Some ValueObjects don't have types (like registers sets). Only print the
239061da546Spatrick // type if there is one to print
240061da546Spatrick ConstString type_name;
241061da546Spatrick if (m_compiler_type.IsValid()) {
242dda28197Spatrick type_name = m_options.m_use_type_display_name
243dda28197Spatrick ? m_valobj->GetDisplayTypeName()
244dda28197Spatrick : m_valobj->GetQualifiedTypeName();
245061da546Spatrick } else {
246061da546Spatrick // only show an invalid type name if the user explicitly triggered
247061da546Spatrick // show_type
248061da546Spatrick if (m_options.m_show_types)
249061da546Spatrick type_name = ConstString("<invalid type>");
250061da546Spatrick }
251061da546Spatrick
252061da546Spatrick if (type_name) {
253061da546Spatrick std::string type_name_str(type_name.GetCString());
254061da546Spatrick if (m_options.m_hide_pointer_value) {
255061da546Spatrick for (auto iter = type_name_str.find(" *"); iter != std::string::npos;
256061da546Spatrick iter = type_name_str.find(" *")) {
257061da546Spatrick type_name_str.erase(iter, 2);
258061da546Spatrick }
259061da546Spatrick }
260dda28197Spatrick typeName << type_name_str.c_str();
261061da546Spatrick }
262061da546Spatrick }
263061da546Spatrick
264061da546Spatrick StreamString varName;
265061da546Spatrick
266061da546Spatrick if (!m_options.m_hide_name) {
267dda28197Spatrick if (m_options.m_flat_output)
268dda28197Spatrick m_valobj->GetExpressionPath(varName);
269dda28197Spatrick else
270dda28197Spatrick varName << GetRootNameForDisplay();
271061da546Spatrick }
272061da546Spatrick
273061da546Spatrick bool decl_printed = false;
274061da546Spatrick if (!m_options.m_decl_printing_helper) {
275061da546Spatrick // if the user didn't give us a custom helper, pick one based upon the
276061da546Spatrick // language, either the one that this printer is bound to, or the preferred
277061da546Spatrick // one for the ValueObject
278061da546Spatrick lldb::LanguageType lang_type =
279061da546Spatrick (m_options.m_varformat_language == lldb::eLanguageTypeUnknown)
280061da546Spatrick ? m_valobj->GetPreferredDisplayLanguage()
281061da546Spatrick : m_options.m_varformat_language;
282061da546Spatrick if (Language *lang_plugin = Language::FindPlugin(lang_type)) {
283061da546Spatrick m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper();
284061da546Spatrick }
285061da546Spatrick }
286061da546Spatrick
287061da546Spatrick if (m_options.m_decl_printing_helper) {
288061da546Spatrick ConstString type_name_cstr(typeName.GetString());
289061da546Spatrick ConstString var_name_cstr(varName.GetString());
290061da546Spatrick
291061da546Spatrick StreamString dest_stream;
292061da546Spatrick if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr,
293061da546Spatrick m_options, dest_stream)) {
294061da546Spatrick decl_printed = true;
295061da546Spatrick m_stream->PutCString(dest_stream.GetString());
296061da546Spatrick }
297061da546Spatrick }
298061da546Spatrick
299061da546Spatrick // if the helper failed, or there is none, do a default thing
300061da546Spatrick if (!decl_printed) {
301061da546Spatrick if (!typeName.Empty())
302061da546Spatrick m_stream->Printf("(%s) ", typeName.GetData());
303061da546Spatrick if (!varName.Empty())
304061da546Spatrick m_stream->Printf("%s =", varName.GetData());
305061da546Spatrick else if (!m_options.m_hide_name)
306061da546Spatrick m_stream->Printf(" =");
307061da546Spatrick }
308061da546Spatrick }
309061da546Spatrick
CheckScopeIfNeeded()310061da546Spatrick bool ValueObjectPrinter::CheckScopeIfNeeded() {
311061da546Spatrick if (m_options.m_scope_already_checked)
312061da546Spatrick return true;
313061da546Spatrick return m_valobj->IsInScope();
314061da546Spatrick }
315061da546Spatrick
GetSummaryFormatter(bool null_if_omitted)316061da546Spatrick TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) {
317061da546Spatrick if (!m_summary_formatter.second) {
318061da546Spatrick TypeSummaryImpl *entry = m_options.m_summary_sp
319061da546Spatrick ? m_options.m_summary_sp.get()
320061da546Spatrick : m_valobj->GetSummaryFormat().get();
321061da546Spatrick
322061da546Spatrick if (m_options.m_omit_summary_depth > 0)
323061da546Spatrick entry = nullptr;
324061da546Spatrick m_summary_formatter.first = entry;
325061da546Spatrick m_summary_formatter.second = true;
326061da546Spatrick }
327061da546Spatrick if (m_options.m_omit_summary_depth > 0 && null_if_omitted)
328061da546Spatrick return nullptr;
329061da546Spatrick return m_summary_formatter.first;
330061da546Spatrick }
331061da546Spatrick
IsPointerValue(const CompilerType & type)332061da546Spatrick static bool IsPointerValue(const CompilerType &type) {
333061da546Spatrick Flags type_flags(type.GetTypeInfo());
334061da546Spatrick if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer))
335061da546Spatrick return type_flags.AllClear(eTypeIsBuiltIn);
336061da546Spatrick return false;
337061da546Spatrick }
338061da546Spatrick
GetValueSummaryError(std::string & value,std::string & summary,std::string & error)339061da546Spatrick void ValueObjectPrinter::GetValueSummaryError(std::string &value,
340061da546Spatrick std::string &summary,
341061da546Spatrick std::string &error) {
342061da546Spatrick lldb::Format format = m_options.m_format;
343061da546Spatrick // if I am printing synthetized elements, apply the format to those elements
344061da546Spatrick // only
345061da546Spatrick if (m_options.m_pointer_as_array)
346061da546Spatrick m_valobj->GetValueAsCString(lldb::eFormatDefault, value);
347061da546Spatrick else if (format != eFormatDefault && format != m_valobj->GetFormat())
348061da546Spatrick m_valobj->GetValueAsCString(format, value);
349061da546Spatrick else {
350061da546Spatrick const char *val_cstr = m_valobj->GetValueAsCString();
351061da546Spatrick if (val_cstr)
352061da546Spatrick value.assign(val_cstr);
353061da546Spatrick }
354061da546Spatrick const char *err_cstr = m_valobj->GetError().AsCString();
355061da546Spatrick if (err_cstr)
356061da546Spatrick error.assign(err_cstr);
357061da546Spatrick
358be691f3bSpatrick if (!ShouldPrintValueObject())
359be691f3bSpatrick return;
360be691f3bSpatrick
361be691f3bSpatrick if (IsNil()) {
362be691f3bSpatrick lldb::LanguageType lang_type =
363be691f3bSpatrick (m_options.m_varformat_language == lldb::eLanguageTypeUnknown)
364be691f3bSpatrick ? m_valobj->GetPreferredDisplayLanguage()
365be691f3bSpatrick : m_options.m_varformat_language;
366be691f3bSpatrick if (Language *lang_plugin = Language::FindPlugin(lang_type)) {
367be691f3bSpatrick summary.assign(lang_plugin->GetNilReferenceSummaryString().str());
368be691f3bSpatrick } else {
369be691f3bSpatrick // We treat C as the fallback language rather than as a separate Language
370be691f3bSpatrick // plugin.
371be691f3bSpatrick summary.assign("NULL");
372be691f3bSpatrick }
373be691f3bSpatrick } else if (IsUninitialized()) {
374061da546Spatrick summary.assign("<uninitialized>");
375be691f3bSpatrick } else if (m_options.m_omit_summary_depth == 0) {
376061da546Spatrick TypeSummaryImpl *entry = GetSummaryFormatter();
377be691f3bSpatrick if (entry) {
378061da546Spatrick m_valobj->GetSummaryAsCString(entry, summary,
379061da546Spatrick m_options.m_varformat_language);
380be691f3bSpatrick } else {
381061da546Spatrick const char *sum_cstr =
382061da546Spatrick m_valobj->GetSummaryAsCString(m_options.m_varformat_language);
383061da546Spatrick if (sum_cstr)
384061da546Spatrick summary.assign(sum_cstr);
385061da546Spatrick }
386061da546Spatrick }
387061da546Spatrick }
388061da546Spatrick
PrintValueAndSummaryIfNeeded(bool & value_printed,bool & summary_printed)389061da546Spatrick bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,
390061da546Spatrick bool &summary_printed) {
391061da546Spatrick bool error_printed = false;
392061da546Spatrick if (ShouldPrintValueObject()) {
393061da546Spatrick if (!CheckScopeIfNeeded())
394061da546Spatrick m_error.assign("out of scope");
395061da546Spatrick if (m_error.empty()) {
396061da546Spatrick GetValueSummaryError(m_value, m_summary, m_error);
397061da546Spatrick }
398061da546Spatrick if (m_error.size()) {
399061da546Spatrick // we need to support scenarios in which it is actually fine for a value
400061da546Spatrick // to have no type but - on the other hand - if we get an error *AND*
401061da546Spatrick // have no type, we try to get out gracefully, since most often that
402061da546Spatrick // combination means "could not resolve a type" and the default failure
403061da546Spatrick // mode is quite ugly
404061da546Spatrick if (!m_compiler_type.IsValid()) {
405061da546Spatrick m_stream->Printf(" <could not resolve type>");
406061da546Spatrick return false;
407061da546Spatrick }
408061da546Spatrick
409061da546Spatrick error_printed = true;
410061da546Spatrick m_stream->Printf(" <%s>\n", m_error.c_str());
411061da546Spatrick } else {
412061da546Spatrick // Make sure we have a value and make sure the summary didn't specify
413061da546Spatrick // that the value should not be printed - and do not print the value if
414061da546Spatrick // this thing is nil (but show the value if the user passes a format
415061da546Spatrick // explicitly)
416061da546Spatrick TypeSummaryImpl *entry = GetSummaryFormatter();
417be691f3bSpatrick const bool has_nil_or_uninitialized_summary =
418be691f3bSpatrick (IsNil() || IsUninitialized()) && !m_summary.empty();
419be691f3bSpatrick if (!has_nil_or_uninitialized_summary && !m_value.empty() &&
420061da546Spatrick (entry == nullptr ||
421061da546Spatrick (entry->DoesPrintValue(m_valobj) ||
422061da546Spatrick m_options.m_format != eFormatDefault) ||
423061da546Spatrick m_summary.empty()) &&
424061da546Spatrick !m_options.m_hide_value) {
425061da546Spatrick if (m_options.m_hide_pointer_value &&
426061da546Spatrick IsPointerValue(m_valobj->GetCompilerType())) {
427061da546Spatrick } else {
428061da546Spatrick m_stream->Printf(" %s", m_value.c_str());
429061da546Spatrick value_printed = true;
430061da546Spatrick }
431061da546Spatrick }
432061da546Spatrick
433061da546Spatrick if (m_summary.size()) {
434061da546Spatrick m_stream->Printf(" %s", m_summary.c_str());
435061da546Spatrick summary_printed = true;
436061da546Spatrick }
437061da546Spatrick }
438061da546Spatrick }
439061da546Spatrick return !error_printed;
440061da546Spatrick }
441061da546Spatrick
PrintObjectDescriptionIfNeeded(bool value_printed,bool summary_printed)442061da546Spatrick bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
443061da546Spatrick bool summary_printed) {
444061da546Spatrick if (ShouldPrintValueObject()) {
445061da546Spatrick // let's avoid the overly verbose no description error for a nil thing
446061da546Spatrick if (m_options.m_use_objc && !IsNil() && !IsUninitialized() &&
447061da546Spatrick (!m_options.m_pointer_as_array)) {
448061da546Spatrick if (!m_options.m_hide_value || !m_options.m_hide_name)
449061da546Spatrick m_stream->Printf(" ");
450061da546Spatrick const char *object_desc = nullptr;
451061da546Spatrick if (value_printed || summary_printed)
452061da546Spatrick object_desc = m_valobj->GetObjectDescription();
453061da546Spatrick else
454061da546Spatrick object_desc = GetDescriptionForDisplay();
455061da546Spatrick if (object_desc && *object_desc) {
456061da546Spatrick // If the description already ends with a \n don't add another one.
457061da546Spatrick size_t object_end = strlen(object_desc) - 1;
458061da546Spatrick if (object_desc[object_end] == '\n')
459061da546Spatrick m_stream->Printf("%s", object_desc);
460061da546Spatrick else
461061da546Spatrick m_stream->Printf("%s\n", object_desc);
462061da546Spatrick return true;
463061da546Spatrick } else if (!value_printed && !summary_printed)
464061da546Spatrick return true;
465061da546Spatrick else
466061da546Spatrick return false;
467061da546Spatrick }
468061da546Spatrick }
469061da546Spatrick return true;
470061da546Spatrick }
471061da546Spatrick
CanAllowExpansion() const472061da546Spatrick bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
473061da546Spatrick switch (m_mode) {
474061da546Spatrick case Mode::Always:
475061da546Spatrick case Mode::Default:
476061da546Spatrick return m_count > 0;
477061da546Spatrick case Mode::Never:
478061da546Spatrick return false;
479061da546Spatrick }
480061da546Spatrick return false;
481061da546Spatrick }
482061da546Spatrick
ShouldPrintChildren(bool is_failed_description,DumpValueObjectOptions::PointerDepth & curr_ptr_depth)483061da546Spatrick bool ValueObjectPrinter::ShouldPrintChildren(
484061da546Spatrick bool is_failed_description,
485061da546Spatrick DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
486061da546Spatrick const bool is_ref = IsRef();
487061da546Spatrick const bool is_ptr = IsPtr();
488061da546Spatrick const bool is_uninit = IsUninitialized();
489061da546Spatrick
490061da546Spatrick if (is_uninit)
491061da546Spatrick return false;
492061da546Spatrick
493061da546Spatrick // if the user has specified an element count, always print children as it is
494061da546Spatrick // explicit user demand being honored
495061da546Spatrick if (m_options.m_pointer_as_array)
496061da546Spatrick return true;
497061da546Spatrick
498061da546Spatrick TypeSummaryImpl *entry = GetSummaryFormatter();
499061da546Spatrick
500061da546Spatrick if (m_options.m_use_objc)
501061da546Spatrick return false;
502061da546Spatrick
503*f6aab3d8Srobert if (is_failed_description || !HasReachedMaximumDepth()) {
504061da546Spatrick // We will show children for all concrete types. We won't show pointer
505061da546Spatrick // contents unless a pointer depth has been specified. We won't reference
506061da546Spatrick // contents unless the reference is the root object (depth of zero).
507061da546Spatrick
508061da546Spatrick // Use a new temporary pointer depth in case we override the current
509061da546Spatrick // pointer depth below...
510061da546Spatrick
511061da546Spatrick if (is_ptr || is_ref) {
512061da546Spatrick // We have a pointer or reference whose value is an address. Make sure
513061da546Spatrick // that address is not NULL
514061da546Spatrick AddressType ptr_address_type;
515061da546Spatrick if (m_valobj->GetPointerValue(&ptr_address_type) == 0)
516061da546Spatrick return false;
517061da546Spatrick
518061da546Spatrick const bool is_root_level = m_curr_depth == 0;
519061da546Spatrick
520061da546Spatrick if (is_ref && is_root_level) {
521061da546Spatrick // If this is the root object (depth is zero) that we are showing and
522061da546Spatrick // it is a reference, and no pointer depth has been supplied print out
523061da546Spatrick // what it references. Don't do this at deeper depths otherwise we can
524061da546Spatrick // end up with infinite recursion...
525061da546Spatrick return true;
526061da546Spatrick }
527061da546Spatrick
528061da546Spatrick return curr_ptr_depth.CanAllowExpansion();
529061da546Spatrick }
530061da546Spatrick
531061da546Spatrick return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty());
532061da546Spatrick }
533061da546Spatrick return false;
534061da546Spatrick }
535061da546Spatrick
ShouldExpandEmptyAggregates()536061da546Spatrick bool ValueObjectPrinter::ShouldExpandEmptyAggregates() {
537061da546Spatrick TypeSummaryImpl *entry = GetSummaryFormatter();
538061da546Spatrick
539061da546Spatrick if (!entry)
540061da546Spatrick return true;
541061da546Spatrick
542061da546Spatrick return entry->DoesPrintEmptyAggregates();
543061da546Spatrick }
544061da546Spatrick
GetValueObjectForChildrenGeneration()545061da546Spatrick ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() {
546061da546Spatrick return m_valobj;
547061da546Spatrick }
548061da546Spatrick
PrintChildrenPreamble()549061da546Spatrick void ValueObjectPrinter::PrintChildrenPreamble() {
550061da546Spatrick if (m_options.m_flat_output) {
551061da546Spatrick if (ShouldPrintValueObject())
552061da546Spatrick m_stream->EOL();
553061da546Spatrick } else {
554061da546Spatrick if (ShouldPrintValueObject())
555061da546Spatrick m_stream->PutCString(IsRef() ? ": {\n" : " {\n");
556061da546Spatrick m_stream->IndentMore();
557061da546Spatrick }
558061da546Spatrick }
559061da546Spatrick
PrintChild(ValueObjectSP child_sp,const DumpValueObjectOptions::PointerDepth & curr_ptr_depth)560061da546Spatrick void ValueObjectPrinter::PrintChild(
561061da546Spatrick ValueObjectSP child_sp,
562061da546Spatrick const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
563061da546Spatrick const uint32_t consumed_depth = (!m_options.m_pointer_as_array) ? 1 : 0;
564061da546Spatrick const bool does_consume_ptr_depth =
565061da546Spatrick ((IsPtr() && !m_options.m_pointer_as_array) || IsRef());
566061da546Spatrick
567061da546Spatrick DumpValueObjectOptions child_options(m_options);
568061da546Spatrick child_options.SetFormat(m_options.m_format)
569061da546Spatrick .SetSummary()
570061da546Spatrick .SetRootValueObjectName();
571061da546Spatrick child_options.SetScopeChecked(true)
572061da546Spatrick .SetHideName(m_options.m_hide_name)
573061da546Spatrick .SetHideValue(m_options.m_hide_value)
574061da546Spatrick .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1
575061da546Spatrick ? child_options.m_omit_summary_depth -
576061da546Spatrick consumed_depth
577061da546Spatrick : 0)
578061da546Spatrick .SetElementCount(0);
579061da546Spatrick
580061da546Spatrick if (child_sp.get()) {
581061da546Spatrick ValueObjectPrinter child_printer(
582061da546Spatrick child_sp.get(), m_stream, child_options,
583061da546Spatrick does_consume_ptr_depth ? --curr_ptr_depth : curr_ptr_depth,
584061da546Spatrick m_curr_depth + consumed_depth, m_printed_instance_pointers);
585061da546Spatrick child_printer.PrintValueObject();
586061da546Spatrick }
587061da546Spatrick }
588061da546Spatrick
GetMaxNumChildrenToPrint(bool & print_dotdotdot)589061da546Spatrick uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) {
590061da546Spatrick ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
591061da546Spatrick
592061da546Spatrick if (m_options.m_pointer_as_array)
593061da546Spatrick return m_options.m_pointer_as_array.m_element_count;
594061da546Spatrick
595061da546Spatrick size_t num_children = synth_m_valobj->GetNumChildren();
596061da546Spatrick print_dotdotdot = false;
597061da546Spatrick if (num_children) {
598061da546Spatrick const size_t max_num_children =
599061da546Spatrick m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
600061da546Spatrick
601061da546Spatrick if (num_children > max_num_children && !m_options.m_ignore_cap) {
602061da546Spatrick print_dotdotdot = true;
603061da546Spatrick return max_num_children;
604061da546Spatrick }
605061da546Spatrick }
606061da546Spatrick return num_children;
607061da546Spatrick }
608061da546Spatrick
PrintChildrenPostamble(bool print_dotdotdot)609061da546Spatrick void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) {
610061da546Spatrick if (!m_options.m_flat_output) {
611061da546Spatrick if (print_dotdotdot) {
612061da546Spatrick m_valobj->GetTargetSP()
613061da546Spatrick ->GetDebugger()
614061da546Spatrick .GetCommandInterpreter()
615061da546Spatrick .ChildrenTruncated();
616061da546Spatrick m_stream->Indent("...\n");
617061da546Spatrick }
618061da546Spatrick m_stream->IndentLess();
619061da546Spatrick m_stream->Indent("}\n");
620061da546Spatrick }
621061da546Spatrick }
622061da546Spatrick
ShouldPrintEmptyBrackets(bool value_printed,bool summary_printed)623061da546Spatrick bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed,
624061da546Spatrick bool summary_printed) {
625061da546Spatrick ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
626061da546Spatrick
627061da546Spatrick if (!IsAggregate())
628061da546Spatrick return false;
629061da546Spatrick
630061da546Spatrick if (!m_options.m_reveal_empty_aggregates) {
631061da546Spatrick if (value_printed || summary_printed)
632061da546Spatrick return false;
633061da546Spatrick }
634061da546Spatrick
635061da546Spatrick if (synth_m_valobj->MightHaveChildren())
636061da546Spatrick return true;
637061da546Spatrick
638061da546Spatrick if (m_val_summary_ok)
639061da546Spatrick return false;
640061da546Spatrick
641061da546Spatrick return true;
642061da546Spatrick }
643061da546Spatrick
PhysicalIndexForLogicalIndex(size_t base,size_t stride,size_t logical)644061da546Spatrick static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride,
645061da546Spatrick size_t logical) {
646061da546Spatrick return base + logical * stride;
647061da546Spatrick }
648061da546Spatrick
GenerateChild(ValueObject * synth_valobj,size_t idx)649061da546Spatrick ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject *synth_valobj,
650061da546Spatrick size_t idx) {
651061da546Spatrick if (m_options.m_pointer_as_array) {
652061da546Spatrick // if generating pointer-as-array children, use GetSyntheticArrayMember
653061da546Spatrick return synth_valobj->GetSyntheticArrayMember(
654061da546Spatrick PhysicalIndexForLogicalIndex(
655061da546Spatrick m_options.m_pointer_as_array.m_base_element,
656061da546Spatrick m_options.m_pointer_as_array.m_stride, idx),
657061da546Spatrick true);
658061da546Spatrick } else {
659061da546Spatrick // otherwise, do the usual thing
660061da546Spatrick return synth_valobj->GetChildAtIndex(idx, true);
661061da546Spatrick }
662061da546Spatrick }
663061da546Spatrick
PrintChildren(bool value_printed,bool summary_printed,const DumpValueObjectOptions::PointerDepth & curr_ptr_depth)664061da546Spatrick void ValueObjectPrinter::PrintChildren(
665061da546Spatrick bool value_printed, bool summary_printed,
666061da546Spatrick const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
667061da546Spatrick ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
668061da546Spatrick
669061da546Spatrick bool print_dotdotdot = false;
670061da546Spatrick size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
671061da546Spatrick if (num_children) {
672061da546Spatrick bool any_children_printed = false;
673061da546Spatrick
674061da546Spatrick for (size_t idx = 0; idx < num_children; ++idx) {
675061da546Spatrick if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) {
676061da546Spatrick if (!any_children_printed) {
677061da546Spatrick PrintChildrenPreamble();
678061da546Spatrick any_children_printed = true;
679061da546Spatrick }
680061da546Spatrick PrintChild(child_sp, curr_ptr_depth);
681061da546Spatrick }
682061da546Spatrick }
683061da546Spatrick
684061da546Spatrick if (any_children_printed)
685061da546Spatrick PrintChildrenPostamble(print_dotdotdot);
686061da546Spatrick else {
687061da546Spatrick if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {
688061da546Spatrick if (ShouldPrintValueObject())
689061da546Spatrick m_stream->PutCString(" {}\n");
690061da546Spatrick else
691061da546Spatrick m_stream->EOL();
692061da546Spatrick } else
693061da546Spatrick m_stream->EOL();
694061da546Spatrick }
695061da546Spatrick } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {
696061da546Spatrick // Aggregate, no children...
697061da546Spatrick if (ShouldPrintValueObject()) {
698061da546Spatrick // if it has a synthetic value, then don't print {}, the synthetic
699061da546Spatrick // children are probably only being used to vend a value
700061da546Spatrick if (m_valobj->DoesProvideSyntheticValue() ||
701061da546Spatrick !ShouldExpandEmptyAggregates())
702061da546Spatrick m_stream->PutCString("\n");
703061da546Spatrick else
704061da546Spatrick m_stream->PutCString(" {}\n");
705061da546Spatrick }
706061da546Spatrick } else {
707061da546Spatrick if (ShouldPrintValueObject())
708061da546Spatrick m_stream->EOL();
709061da546Spatrick }
710061da546Spatrick }
711061da546Spatrick
PrintChildrenOneLiner(bool hide_names)712061da546Spatrick bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
713061da546Spatrick if (!GetMostSpecializedValue() || m_valobj == nullptr)
714061da546Spatrick return false;
715061da546Spatrick
716061da546Spatrick ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration();
717061da546Spatrick
718061da546Spatrick bool print_dotdotdot = false;
719061da546Spatrick size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
720061da546Spatrick
721061da546Spatrick if (num_children) {
722061da546Spatrick m_stream->PutChar('(');
723061da546Spatrick
724061da546Spatrick for (uint32_t idx = 0; idx < num_children; ++idx) {
725061da546Spatrick lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true));
726061da546Spatrick if (child_sp)
727061da546Spatrick child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
728061da546Spatrick m_options.m_use_dynamic, m_options.m_use_synthetic);
729061da546Spatrick if (child_sp) {
730061da546Spatrick if (idx)
731061da546Spatrick m_stream->PutCString(", ");
732061da546Spatrick if (!hide_names) {
733061da546Spatrick const char *name = child_sp.get()->GetName().AsCString();
734061da546Spatrick if (name && *name) {
735061da546Spatrick m_stream->PutCString(name);
736061da546Spatrick m_stream->PutCString(" = ");
737061da546Spatrick }
738061da546Spatrick }
739061da546Spatrick child_sp->DumpPrintableRepresentation(
740061da546Spatrick *m_stream, ValueObject::eValueObjectRepresentationStyleSummary,
741061da546Spatrick m_options.m_format,
742061da546Spatrick ValueObject::PrintableRepresentationSpecialCases::eDisable);
743061da546Spatrick }
744061da546Spatrick }
745061da546Spatrick
746061da546Spatrick if (print_dotdotdot)
747061da546Spatrick m_stream->PutCString(", ...)");
748061da546Spatrick else
749061da546Spatrick m_stream->PutChar(')');
750061da546Spatrick }
751061da546Spatrick return true;
752061da546Spatrick }
753061da546Spatrick
PrintChildrenIfNeeded(bool value_printed,bool summary_printed)754061da546Spatrick void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
755061da546Spatrick bool summary_printed) {
756061da546Spatrick // This flag controls whether we tried to display a description for this
757061da546Spatrick // object and failed if that happens, we want to display the children if any.
758061da546Spatrick bool is_failed_description =
759061da546Spatrick !PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
760061da546Spatrick
761061da546Spatrick DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth;
762061da546Spatrick const bool print_children =
763061da546Spatrick ShouldPrintChildren(is_failed_description, curr_ptr_depth);
764061da546Spatrick const bool print_oneline =
765061da546Spatrick (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types ||
766061da546Spatrick !m_options.m_allow_oneliner_mode || m_options.m_flat_output ||
767061da546Spatrick (m_options.m_pointer_as_array) || m_options.m_show_location)
768061da546Spatrick ? false
769061da546Spatrick : DataVisualization::ShouldPrintAsOneLiner(*m_valobj);
770061da546Spatrick if (print_children && IsInstancePointer()) {
771061da546Spatrick uint64_t instance_ptr_value = m_valobj->GetValueAsUnsigned(0);
772061da546Spatrick if (m_printed_instance_pointers->count(instance_ptr_value)) {
773061da546Spatrick // We already printed this instance-is-pointer thing, so don't expand it.
774061da546Spatrick m_stream->PutCString(" {...}\n");
775061da546Spatrick return;
776061da546Spatrick } else {
777061da546Spatrick // Remember this guy for future reference.
778061da546Spatrick m_printed_instance_pointers->emplace(instance_ptr_value);
779061da546Spatrick }
780061da546Spatrick }
781061da546Spatrick
782061da546Spatrick if (print_children) {
783061da546Spatrick if (print_oneline) {
784061da546Spatrick m_stream->PutChar(' ');
785061da546Spatrick PrintChildrenOneLiner(false);
786061da546Spatrick m_stream->EOL();
787061da546Spatrick } else
788061da546Spatrick PrintChildren(value_printed, summary_printed, curr_ptr_depth);
789*f6aab3d8Srobert } else if (HasReachedMaximumDepth() && IsAggregate() &&
790061da546Spatrick ShouldPrintValueObject()) {
791061da546Spatrick m_stream->PutCString("{...}\n");
792*f6aab3d8Srobert // The maximum child depth has been reached. If `m_max_depth` is the default
793*f6aab3d8Srobert // (i.e. the user has _not_ customized it), then lldb presents a warning to
794*f6aab3d8Srobert // the user. The warning tells the user that the limit has been reached, but
795*f6aab3d8Srobert // more importantly tells them how to expand the limit if desired.
796*f6aab3d8Srobert if (m_options.m_max_depth_is_default)
797*f6aab3d8Srobert m_valobj->GetTargetSP()
798*f6aab3d8Srobert ->GetDebugger()
799*f6aab3d8Srobert .GetCommandInterpreter()
800*f6aab3d8Srobert .SetReachedMaximumDepth();
801061da546Spatrick } else
802061da546Spatrick m_stream->EOL();
803061da546Spatrick }
804*f6aab3d8Srobert
HasReachedMaximumDepth()805*f6aab3d8Srobert bool ValueObjectPrinter::HasReachedMaximumDepth() {
806*f6aab3d8Srobert return m_curr_depth >= m_options.m_max_depth;
807*f6aab3d8Srobert }
808