Create a new "lldb_private::CompilerDeclContext" class that will replace all direct uses of "clang::DeclContext" when used in compiler agnostic code, yet still allow for conversion to clang::DeclContext subclasses by clang specific code. This completes the abstraction of type parsing by removing all "clang::" references from the SymbolFileDWARF. The new "lldb_private::CompilerDeclContext" class abstracts decl contexts found in compiler type systems so they can be used in internal API calls. The TypeSystem is required to support CompilerDeclContexts with new pure virtual functions that start with "DeclContext" in the member function names. Converted all code that used lldb_private::ClangNamespaceDecl over to use the new CompilerDeclContext class and removed the ClangNamespaceDecl.cpp and ClangNamespaceDecl.h files.
Removed direct use of clang APIs from SBType and now use the abstract type systems to correctly explore types.
Bulk renames for things that used to return a ClangASTType which is now CompilerType:
"Type::GetClangFullType()" to "Type::GetFullCompilerType()"
"Type::GetClangLayoutType()" to "Type::GetLayoutCompilerType()"
"Type::GetClangForwardType()" to "Type::GetForwardCompilerType()"
"Value::GetClangType()" to "Value::GetCompilerType()"
"Value::SetClangType (const CompilerType &)" to "Value::SetCompilerType (const CompilerType &)"
"ValueObject::GetClangType ()" to "ValueObject::GetCompilerType()"
many more renames that are similar.
llvm-svn: 245905
773 lines
23 KiB
C++
773 lines
23 KiB
C++
//===-- ValueObjectPrinter.cpp -------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/DataFormatters/ValueObjectPrinter.h"
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/DataFormatters/DataVisualization.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Target/Target.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
DumpValueObjectOptions::DumpValueObjectOptions (ValueObject& valobj) :
|
|
DumpValueObjectOptions()
|
|
{
|
|
m_use_dynamic = valobj.GetDynamicValueType();
|
|
m_use_synthetic = valobj.IsSynthetic();
|
|
}
|
|
|
|
ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj,
|
|
Stream* s)
|
|
{
|
|
if (valobj)
|
|
{
|
|
DumpValueObjectOptions options(*valobj);
|
|
Init (valobj,s,options,options.m_max_ptr_depth,0);
|
|
}
|
|
else
|
|
{
|
|
DumpValueObjectOptions options;
|
|
Init (valobj,s,options,options.m_max_ptr_depth,0);
|
|
}
|
|
}
|
|
|
|
ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj,
|
|
Stream* s,
|
|
const DumpValueObjectOptions& options)
|
|
{
|
|
Init(valobj,s,options,options.m_max_ptr_depth,0);
|
|
}
|
|
|
|
ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj,
|
|
Stream* s,
|
|
const DumpValueObjectOptions& options,
|
|
const DumpValueObjectOptions::PointerDepth& ptr_depth,
|
|
uint32_t curr_depth)
|
|
{
|
|
Init(valobj,s,options,ptr_depth,curr_depth);
|
|
}
|
|
|
|
void
|
|
ValueObjectPrinter::Init (ValueObject* valobj,
|
|
Stream* s,
|
|
const DumpValueObjectOptions& options,
|
|
const DumpValueObjectOptions::PointerDepth& ptr_depth,
|
|
uint32_t curr_depth)
|
|
{
|
|
m_orig_valobj = valobj;
|
|
m_valobj = nullptr;
|
|
m_stream = s;
|
|
this->options = options;
|
|
m_ptr_depth = ptr_depth;
|
|
m_curr_depth = curr_depth;
|
|
assert (m_orig_valobj && "cannot print a NULL ValueObject");
|
|
assert (m_stream && "cannot print to a NULL Stream");
|
|
m_should_print = eLazyBoolCalculate;
|
|
m_is_nil = eLazyBoolCalculate;
|
|
m_is_ptr = eLazyBoolCalculate;
|
|
m_is_ref = eLazyBoolCalculate;
|
|
m_is_aggregate = eLazyBoolCalculate;
|
|
m_summary_formatter = {nullptr,false};
|
|
m_value.assign("");
|
|
m_summary.assign("");
|
|
m_error.assign("");
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintValueObject ()
|
|
{
|
|
if (!GetMostSpecializedValue () || m_valobj == nullptr)
|
|
return false;
|
|
|
|
if (ShouldPrintValueObject())
|
|
{
|
|
PrintValidationMarkerIfNeeded();
|
|
|
|
PrintLocationIfNeeded();
|
|
m_stream->Indent();
|
|
|
|
bool show_type = PrintTypeIfNeeded();
|
|
|
|
PrintNameIfNeeded(show_type);
|
|
}
|
|
|
|
bool value_printed = false;
|
|
bool summary_printed = false;
|
|
|
|
bool val_summary_ok = PrintValueAndSummaryIfNeeded (value_printed,summary_printed);
|
|
|
|
if (val_summary_ok)
|
|
PrintChildrenIfNeeded (value_printed, summary_printed);
|
|
else
|
|
m_stream->EOL();
|
|
|
|
PrintValidationErrorIfNeeded();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::GetMostSpecializedValue ()
|
|
{
|
|
if (m_valobj)
|
|
return true;
|
|
bool update_success = m_orig_valobj->UpdateValueIfNeeded (true);
|
|
if (!update_success)
|
|
{
|
|
m_valobj = m_orig_valobj;
|
|
}
|
|
else
|
|
{
|
|
if (m_orig_valobj->IsDynamic())
|
|
{
|
|
if (options.m_use_dynamic == eNoDynamicValues)
|
|
{
|
|
ValueObject *static_value = m_orig_valobj->GetStaticValue().get();
|
|
if (static_value)
|
|
m_valobj = static_value;
|
|
else
|
|
m_valobj = m_orig_valobj;
|
|
}
|
|
else
|
|
m_valobj = m_orig_valobj;
|
|
}
|
|
else
|
|
{
|
|
if (options.m_use_dynamic != eNoDynamicValues)
|
|
{
|
|
ValueObject *dynamic_value = m_orig_valobj->GetDynamicValue(options.m_use_dynamic).get();
|
|
if (dynamic_value)
|
|
m_valobj = dynamic_value;
|
|
else
|
|
m_valobj = m_orig_valobj;
|
|
}
|
|
else
|
|
m_valobj = m_orig_valobj;
|
|
}
|
|
|
|
if (m_valobj->IsSynthetic())
|
|
{
|
|
if (options.m_use_synthetic == false)
|
|
{
|
|
ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get();
|
|
if (non_synthetic)
|
|
m_valobj = non_synthetic;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (options.m_use_synthetic == true)
|
|
{
|
|
ValueObject *synthetic = m_valobj->GetSyntheticValue().get();
|
|
if (synthetic)
|
|
m_valobj = synthetic;
|
|
}
|
|
}
|
|
}
|
|
m_clang_type = m_valobj->GetCompilerType();
|
|
m_type_flags = m_clang_type.GetTypeInfo ();
|
|
return true;
|
|
}
|
|
|
|
const char*
|
|
ValueObjectPrinter::GetDescriptionForDisplay ()
|
|
{
|
|
const char* str = m_valobj->GetObjectDescription();
|
|
if (!str)
|
|
str = m_valobj->GetSummaryAsCString();
|
|
if (!str)
|
|
str = m_valobj->GetValueAsCString();
|
|
return str;
|
|
}
|
|
|
|
const char*
|
|
ValueObjectPrinter::GetRootNameForDisplay (const char* if_fail)
|
|
{
|
|
const char *root_valobj_name = options.m_root_valobj_name.empty() ?
|
|
m_valobj->GetName().AsCString() :
|
|
options.m_root_valobj_name.c_str();
|
|
return root_valobj_name ? root_valobj_name : if_fail;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::ShouldPrintValueObject ()
|
|
{
|
|
if (m_should_print == eLazyBoolCalculate)
|
|
m_should_print = (options.m_flat_output == false || m_type_flags.Test (eTypeHasValue)) ? eLazyBoolYes : eLazyBoolNo;
|
|
return m_should_print == eLazyBoolYes;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::IsNil ()
|
|
{
|
|
if (m_is_nil == eLazyBoolCalculate)
|
|
m_is_nil = m_valobj->IsObjCNil() ? eLazyBoolYes : eLazyBoolNo;
|
|
return m_is_nil == eLazyBoolYes;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::IsPtr ()
|
|
{
|
|
if (m_is_ptr == eLazyBoolCalculate)
|
|
m_is_ptr = m_type_flags.Test (eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo;
|
|
return m_is_ptr == eLazyBoolYes;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::IsRef ()
|
|
{
|
|
if (m_is_ref == eLazyBoolCalculate)
|
|
m_is_ref = m_type_flags.Test (eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo;
|
|
return m_is_ref == eLazyBoolYes;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::IsAggregate ()
|
|
{
|
|
if (m_is_aggregate == eLazyBoolCalculate)
|
|
m_is_aggregate = m_type_flags.Test (eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo;
|
|
return m_is_aggregate == eLazyBoolYes;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintLocationIfNeeded ()
|
|
{
|
|
if (options.m_show_location)
|
|
{
|
|
m_stream->Printf("%s: ", m_valobj->GetLocationAsCString());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintTypeIfNeeded ()
|
|
{
|
|
bool show_type = true;
|
|
// if we are at the root-level and been asked to hide the root's type, then hide it
|
|
if (m_curr_depth == 0 && options.m_hide_root_type)
|
|
show_type = false;
|
|
else
|
|
// otherwise decide according to the usual rules (asked to show types - always at the root level)
|
|
show_type = options.m_show_types || (m_curr_depth == 0 && !options.m_flat_output);
|
|
|
|
if (show_type)
|
|
{
|
|
// Some ValueObjects don't have types (like registers sets). Only print
|
|
// the type if there is one to print
|
|
ConstString type_name;
|
|
if (options.m_use_type_display_name)
|
|
type_name = m_valobj->GetDisplayTypeName();
|
|
else
|
|
type_name = m_valobj->GetQualifiedTypeName();
|
|
if (type_name)
|
|
m_stream->Printf("(%s) ", type_name.GetCString());
|
|
else
|
|
show_type = false;
|
|
}
|
|
return show_type;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintNameIfNeeded (bool show_type)
|
|
{
|
|
if (options.m_flat_output)
|
|
{
|
|
// If we are showing types, also qualify the C++ base classes
|
|
const bool qualify_cxx_base_classes = show_type;
|
|
if (!options.m_hide_name)
|
|
{
|
|
m_valobj->GetExpressionPath(*m_stream, qualify_cxx_base_classes);
|
|
m_stream->PutCString(" =");
|
|
return true;
|
|
}
|
|
}
|
|
else if (!options.m_hide_name)
|
|
{
|
|
const char *name_cstr = GetRootNameForDisplay("");
|
|
m_stream->Printf ("%s =", name_cstr);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::CheckScopeIfNeeded ()
|
|
{
|
|
if (options.m_scope_already_checked)
|
|
return true;
|
|
return m_valobj->IsInScope();
|
|
}
|
|
|
|
TypeSummaryImpl*
|
|
ValueObjectPrinter::GetSummaryFormatter ()
|
|
{
|
|
if (m_summary_formatter.second == false)
|
|
{
|
|
TypeSummaryImpl* entry = options.m_summary_sp ? options.m_summary_sp.get() : m_valobj->GetSummaryFormat().get();
|
|
|
|
if (options.m_omit_summary_depth > 0)
|
|
entry = NULL;
|
|
m_summary_formatter.first = entry;
|
|
m_summary_formatter.second = true;
|
|
}
|
|
return m_summary_formatter.first;
|
|
}
|
|
|
|
void
|
|
ValueObjectPrinter::GetValueSummaryError (std::string& value,
|
|
std::string& summary,
|
|
std::string& error)
|
|
{
|
|
if (options.m_format != eFormatDefault && options.m_format != m_valobj->GetFormat())
|
|
{
|
|
m_valobj->GetValueAsCString(options.m_format,
|
|
value);
|
|
}
|
|
else
|
|
{
|
|
const char* val_cstr = m_valobj->GetValueAsCString();
|
|
if (val_cstr)
|
|
value.assign(val_cstr);
|
|
}
|
|
const char* err_cstr = m_valobj->GetError().AsCString();
|
|
if (err_cstr)
|
|
error.assign(err_cstr);
|
|
|
|
if (ShouldPrintValueObject())
|
|
{
|
|
if (IsNil())
|
|
summary.assign("nil");
|
|
else if (options.m_omit_summary_depth == 0)
|
|
{
|
|
TypeSummaryImpl* entry = GetSummaryFormatter();
|
|
if (entry)
|
|
m_valobj->GetSummaryAsCString(entry, summary);
|
|
else
|
|
{
|
|
const char* sum_cstr = m_valobj->GetSummaryAsCString();
|
|
if (sum_cstr)
|
|
summary.assign(sum_cstr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintValueAndSummaryIfNeeded (bool& value_printed,
|
|
bool& summary_printed)
|
|
{
|
|
bool error_printed = false;
|
|
if (ShouldPrintValueObject())
|
|
{
|
|
if (!CheckScopeIfNeeded())
|
|
m_error.assign("out of scope");
|
|
if (m_error.empty())
|
|
{
|
|
GetValueSummaryError(m_value, m_summary, m_error);
|
|
}
|
|
if (m_error.size())
|
|
{
|
|
error_printed = true;
|
|
m_stream->Printf (" <%s>\n", m_error.c_str());
|
|
}
|
|
else
|
|
{
|
|
// Make sure we have a value and make sure the summary didn't
|
|
// specify that the value should not be printed - and do not print
|
|
// the value if this thing is nil
|
|
// (but show the value if the user passes a format explicitly)
|
|
TypeSummaryImpl* entry = GetSummaryFormatter();
|
|
if (!IsNil() && !m_value.empty() && (entry == NULL || (entry->DoesPrintValue(m_valobj) || options.m_format != eFormatDefault) || m_summary.empty()) && !options.m_hide_value)
|
|
{
|
|
m_stream->Printf(" %s", m_value.c_str());
|
|
value_printed = true;
|
|
}
|
|
|
|
if (m_summary.size())
|
|
{
|
|
m_stream->Printf(" %s", m_summary.c_str());
|
|
summary_printed = true;
|
|
}
|
|
}
|
|
}
|
|
return !error_printed;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintObjectDescriptionIfNeeded (bool value_printed,
|
|
bool summary_printed)
|
|
{
|
|
if (ShouldPrintValueObject())
|
|
{
|
|
// let's avoid the overly verbose no description error for a nil thing
|
|
if (options.m_use_objc && !IsNil())
|
|
{
|
|
if (!options.m_hide_value || !options.m_hide_name)
|
|
m_stream->Printf(" ");
|
|
const char *object_desc = nullptr;
|
|
if (value_printed || summary_printed)
|
|
object_desc = m_valobj->GetObjectDescription();
|
|
else
|
|
object_desc = GetDescriptionForDisplay();
|
|
if (object_desc && *object_desc)
|
|
{
|
|
m_stream->Printf("%s\n", object_desc);
|
|
return true;
|
|
}
|
|
else if (value_printed == false && summary_printed == false)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
DumpValueObjectOptions::PointerDepth::CanAllowExpansion (bool is_root,
|
|
TypeSummaryImpl* entry,
|
|
ValueObject *valobj,
|
|
const std::string& summary)
|
|
{
|
|
switch (m_mode)
|
|
{
|
|
case Mode::Always:
|
|
return (m_count > 0);
|
|
case Mode::Never:
|
|
return false;
|
|
case Mode::Default:
|
|
if (is_root)
|
|
m_count = std::min<decltype(m_count)>(m_count,1);
|
|
return m_count > 0;
|
|
case Mode::Formatters:
|
|
if (!entry || entry->DoesPrintChildren(valobj) || summary.empty())
|
|
return m_count > 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
DumpValueObjectOptions::PointerDepth::CanAllowExpansion () const
|
|
{
|
|
switch (m_mode)
|
|
{
|
|
case Mode::Always:
|
|
case Mode::Default:
|
|
case Mode::Formatters:
|
|
return (m_count > 0);
|
|
case Mode::Never:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description,
|
|
DumpValueObjectOptions::PointerDepth& curr_ptr_depth)
|
|
{
|
|
const bool is_ref = IsRef ();
|
|
const bool is_ptr = IsPtr ();
|
|
|
|
TypeSummaryImpl* entry = GetSummaryFormatter();
|
|
|
|
if (is_failed_description || m_curr_depth < options.m_max_depth)
|
|
{
|
|
// We will show children for all concrete types. We won't show
|
|
// pointer contents unless a pointer depth has been specified.
|
|
// We won't reference contents unless the reference is the
|
|
// root object (depth of zero).
|
|
|
|
// Use a new temporary pointer depth in case we override the
|
|
// current pointer depth below...
|
|
|
|
if (is_ptr || is_ref)
|
|
{
|
|
// We have a pointer or reference whose value is an address.
|
|
// Make sure that address is not NULL
|
|
AddressType ptr_address_type;
|
|
if (m_valobj->GetPointerValue (&ptr_address_type) == 0)
|
|
return false;
|
|
|
|
const bool is_root_level = m_curr_depth == 0;
|
|
|
|
if (is_ref &&
|
|
is_root_level)
|
|
{
|
|
// If this is the root object (depth is zero) that we are showing
|
|
// and it is a reference, and no pointer depth has been supplied
|
|
// print out what it references. Don't do this at deeper depths
|
|
// otherwise we can end up with infinite recursion...
|
|
return true;
|
|
}
|
|
|
|
return curr_ptr_depth.CanAllowExpansion(false, entry, m_valobj, m_summary);
|
|
}
|
|
|
|
return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::ShouldExpandEmptyAggregates ()
|
|
{
|
|
TypeSummaryImpl* entry = GetSummaryFormatter();
|
|
|
|
if (!entry)
|
|
return true;
|
|
|
|
return entry->DoesPrintEmptyAggregates();
|
|
}
|
|
|
|
ValueObject*
|
|
ValueObjectPrinter::GetValueObjectForChildrenGeneration ()
|
|
{
|
|
return m_valobj;
|
|
}
|
|
|
|
void
|
|
ValueObjectPrinter::PrintChildrenPreamble ()
|
|
{
|
|
if (options.m_flat_output)
|
|
{
|
|
if (ShouldPrintValueObject())
|
|
m_stream->EOL();
|
|
}
|
|
else
|
|
{
|
|
if (ShouldPrintValueObject())
|
|
m_stream->PutCString(IsRef () ? ": {\n" : " {\n");
|
|
m_stream->IndentMore();
|
|
}
|
|
}
|
|
|
|
void
|
|
ValueObjectPrinter::PrintChild (ValueObjectSP child_sp,
|
|
const DumpValueObjectOptions::PointerDepth& curr_ptr_depth)
|
|
{
|
|
DumpValueObjectOptions child_options(options);
|
|
child_options.SetFormat(options.m_format).SetSummary().SetRootValueObjectName();
|
|
child_options.SetScopeChecked(true).SetHideName(options.m_hide_name).SetHideValue(options.m_hide_value)
|
|
.SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 ? child_options.m_omit_summary_depth - 1 : 0);
|
|
if (child_sp.get())
|
|
{
|
|
ValueObjectPrinter child_printer(child_sp.get(),
|
|
m_stream,
|
|
child_options,
|
|
(IsPtr() || IsRef()) ? --curr_ptr_depth : curr_ptr_depth,
|
|
m_curr_depth + 1);
|
|
child_printer.PrintValueObject();
|
|
}
|
|
}
|
|
|
|
uint32_t
|
|
ValueObjectPrinter::GetMaxNumChildrenToPrint (bool& print_dotdotdot)
|
|
{
|
|
ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration();
|
|
|
|
size_t num_children = synth_m_valobj->GetNumChildren();
|
|
print_dotdotdot = false;
|
|
if (num_children)
|
|
{
|
|
const size_t max_num_children = m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
|
|
|
|
if (num_children > max_num_children && !options.m_ignore_cap)
|
|
{
|
|
print_dotdotdot = true;
|
|
return max_num_children;
|
|
}
|
|
}
|
|
return num_children;
|
|
}
|
|
|
|
void
|
|
ValueObjectPrinter::PrintChildrenPostamble (bool print_dotdotdot)
|
|
{
|
|
if (!options.m_flat_output)
|
|
{
|
|
if (print_dotdotdot)
|
|
{
|
|
m_valobj->GetTargetSP()->GetDebugger().GetCommandInterpreter().ChildrenTruncated();
|
|
m_stream->Indent("...\n");
|
|
}
|
|
m_stream->IndentLess();
|
|
m_stream->Indent("}\n");
|
|
}
|
|
}
|
|
|
|
void
|
|
ValueObjectPrinter::PrintChildren (bool value_printed,
|
|
bool summary_printed,
|
|
const DumpValueObjectOptions::PointerDepth& curr_ptr_depth)
|
|
{
|
|
ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration();
|
|
|
|
bool print_dotdotdot = false;
|
|
size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
|
|
if (num_children)
|
|
{
|
|
PrintChildrenPreamble ();
|
|
|
|
for (size_t idx=0; idx<num_children; ++idx)
|
|
{
|
|
ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true));
|
|
PrintChild (child_sp, curr_ptr_depth);
|
|
}
|
|
|
|
PrintChildrenPostamble (print_dotdotdot);
|
|
}
|
|
else if (IsAggregate())
|
|
{
|
|
// Aggregate, no children...
|
|
if (ShouldPrintValueObject())
|
|
{
|
|
// if it has a synthetic value, then don't print {}, the synthetic children are probably only being used to vend a value
|
|
if (m_valobj->DoesProvideSyntheticValue() || !ShouldExpandEmptyAggregates())
|
|
m_stream->PutCString( "\n");
|
|
else
|
|
m_stream->PutCString(" {}\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ShouldPrintValueObject())
|
|
m_stream->EOL();
|
|
}
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintChildrenOneLiner (bool hide_names)
|
|
{
|
|
if (!GetMostSpecializedValue () || m_valobj == nullptr)
|
|
return false;
|
|
|
|
ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration();
|
|
|
|
bool print_dotdotdot = false;
|
|
size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot);
|
|
|
|
if (num_children)
|
|
{
|
|
m_stream->PutChar('(');
|
|
|
|
for (uint32_t idx=0; idx<num_children; ++idx)
|
|
{
|
|
lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true));
|
|
if (child_sp)
|
|
child_sp = child_sp->GetQualifiedRepresentationIfAvailable(options.m_use_dynamic, options.m_use_synthetic);
|
|
if (child_sp)
|
|
{
|
|
if (idx)
|
|
m_stream->PutCString(", ");
|
|
if (!hide_names)
|
|
{
|
|
const char* name = child_sp.get()->GetName().AsCString();
|
|
if (name && *name)
|
|
{
|
|
m_stream->PutCString(name);
|
|
m_stream->PutCString(" = ");
|
|
}
|
|
}
|
|
child_sp->DumpPrintableRepresentation(*m_stream,
|
|
ValueObject::eValueObjectRepresentationStyleSummary,
|
|
lldb::eFormatInvalid,
|
|
ValueObject::ePrintableRepresentationSpecialCasesDisable);
|
|
}
|
|
}
|
|
|
|
if (print_dotdotdot)
|
|
m_stream->PutCString(", ...)");
|
|
else
|
|
m_stream->PutChar(')');
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
ValueObjectPrinter::PrintChildrenIfNeeded (bool value_printed,
|
|
bool summary_printed)
|
|
{
|
|
// this flag controls whether we tried to display a description for this object and failed
|
|
// if that happens, we want to display the children, if any
|
|
bool is_failed_description = !PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
|
|
|
|
auto curr_ptr_depth = m_ptr_depth;
|
|
bool print_children = ShouldPrintChildren (is_failed_description,curr_ptr_depth);
|
|
bool print_oneline = (curr_ptr_depth.CanAllowExpansion() ||
|
|
options.m_show_types ||
|
|
!options.m_allow_oneliner_mode ||
|
|
options.m_flat_output ||
|
|
options.m_show_location) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj);
|
|
|
|
if (print_children)
|
|
{
|
|
if (print_oneline)
|
|
{
|
|
m_stream->PutChar(' ');
|
|
PrintChildrenOneLiner (false);
|
|
m_stream->EOL();
|
|
}
|
|
else
|
|
PrintChildren (value_printed, summary_printed, curr_ptr_depth);
|
|
}
|
|
else if (m_curr_depth >= options.m_max_depth && IsAggregate() && ShouldPrintValueObject())
|
|
{
|
|
m_stream->PutCString("{...}\n");
|
|
}
|
|
else
|
|
m_stream->EOL();
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::ShouldPrintValidation ()
|
|
{
|
|
return options.m_run_validator;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintValidationMarkerIfNeeded ()
|
|
{
|
|
if (!ShouldPrintValidation())
|
|
return false;
|
|
|
|
m_validation = m_valobj->GetValidationStatus();
|
|
|
|
if (TypeValidatorResult::Failure == m_validation.first)
|
|
{
|
|
m_stream->Printf("! ");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
ValueObjectPrinter::PrintValidationErrorIfNeeded ()
|
|
{
|
|
if (!ShouldPrintValidation())
|
|
return false;
|
|
|
|
if (TypeValidatorResult::Success == m_validation.first)
|
|
return false;
|
|
|
|
if (m_validation.second.empty())
|
|
m_validation.second.assign("unknown error");
|
|
|
|
m_stream->Printf(" ! validation error: %s", m_validation.second.c_str());
|
|
m_stream->EOL();
|
|
|
|
return true;
|
|
}
|