2013-11-06 11:48:53 -05:00
//===-- 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
2015-12-30 06:55:28 -05:00
# include "lldb/Core/Stream.h"
# include "lldb/Core/ValueObject.h"
2013-11-06 11:48:53 -05:00
# include "lldb/DataFormatters/DataVisualization.h"
# include "lldb/Interpreter/CommandInterpreter.h"
2015-12-30 06:55:28 -05:00
# include "lldb/Target/Language.h"
2013-11-06 11:48:53 -05:00
# include "lldb/Target/Target.h"
using namespace lldb ;
using namespace lldb_private ;
2015-07-03 12:57:06 -04:00
ValueObjectPrinter : : ValueObjectPrinter ( ValueObject * valobj ,
Stream * s )
{
if ( valobj )
{
DumpValueObjectOptions options ( * valobj ) ;
2015-12-30 06:55:28 -05:00
Init ( valobj , s , options , m_options . m_max_ptr_depth , 0 , nullptr ) ;
2015-07-03 12:57:06 -04:00
}
else
{
DumpValueObjectOptions options ;
2015-12-30 06:55:28 -05:00
Init ( valobj , s , options , m_options . m_max_ptr_depth , 0 , nullptr ) ;
2015-07-03 12:57:06 -04:00
}
}
2013-11-06 11:48:53 -05:00
ValueObjectPrinter : : ValueObjectPrinter ( ValueObject * valobj ,
Stream * s ,
const DumpValueObjectOptions & options )
{
2015-12-30 06:55:28 -05:00
Init ( valobj , s , options , m_options . m_max_ptr_depth , 0 , nullptr ) ;
2013-11-06 11:48:53 -05:00
}
ValueObjectPrinter : : ValueObjectPrinter ( ValueObject * valobj ,
Stream * s ,
const DumpValueObjectOptions & options ,
2015-12-30 06:55:28 -05:00
const DumpValueObjectOptions : : PointerDepth & ptr_depth ,
uint32_t curr_depth ,
InstancePointersSetSP printed_instance_pointers )
2013-11-06 11:48:53 -05:00
{
2015-12-30 06:55:28 -05:00
Init ( valobj , s , options , ptr_depth , curr_depth , printed_instance_pointers ) ;
2013-11-06 11:48:53 -05:00
}
void
ValueObjectPrinter : : Init ( ValueObject * valobj ,
Stream * s ,
const DumpValueObjectOptions & options ,
2015-12-30 06:55:28 -05:00
const DumpValueObjectOptions : : PointerDepth & ptr_depth ,
uint32_t curr_depth ,
InstancePointersSetSP printed_instance_pointers )
2013-11-06 11:48:53 -05:00
{
m_orig_valobj = valobj ;
m_valobj = nullptr ;
m_stream = s ;
2015-12-30 06:55:28 -05:00
m_options = options ;
2013-11-06 11:48:53 -05:00
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 ;
2015-12-30 06:55:28 -05:00
m_is_uninit = eLazyBoolCalculate ;
2013-11-06 11:48:53 -05:00
m_is_ptr = eLazyBoolCalculate ;
m_is_ref = eLazyBoolCalculate ;
m_is_aggregate = eLazyBoolCalculate ;
2015-12-30 06:55:28 -05:00
m_is_instance_ptr = eLazyBoolCalculate ;
2013-11-06 11:48:53 -05:00
m_summary_formatter = { nullptr , false } ;
m_value . assign ( " " ) ;
m_summary . assign ( " " ) ;
m_error . assign ( " " ) ;
2015-12-30 06:55:28 -05:00
m_val_summary_ok = false ;
m_printed_instance_pointers = printed_instance_pointers ? printed_instance_pointers : InstancePointersSetSP ( new InstancePointersSet ( ) ) ;
2013-11-06 11:48:53 -05:00
}
bool
ValueObjectPrinter : : PrintValueObject ( )
{
2015-02-06 16:38:51 -05:00
if ( ! GetMostSpecializedValue ( ) | | m_valobj = = nullptr )
2013-11-06 11:48:53 -05:00
return false ;
if ( ShouldPrintValueObject ( ) )
{
2015-02-06 16:38:51 -05:00
PrintValidationMarkerIfNeeded ( ) ;
2013-11-06 11:48:53 -05:00
PrintLocationIfNeeded ( ) ;
m_stream - > Indent ( ) ;
2015-12-30 06:55:28 -05:00
PrintDecl ( ) ;
2013-11-06 11:48:53 -05:00
}
bool value_printed = false ;
bool summary_printed = false ;
2015-12-30 06:55:28 -05:00
m_val_summary_ok = PrintValueAndSummaryIfNeeded ( value_printed , summary_printed ) ;
2013-11-06 11:48:53 -05:00
2015-12-30 06:55:28 -05:00
if ( m_val_summary_ok )
2013-11-06 11:48:53 -05:00
PrintChildrenIfNeeded ( value_printed , summary_printed ) ;
else
m_stream - > EOL ( ) ;
2015-02-06 16:38:51 -05:00
PrintValidationErrorIfNeeded ( ) ;
2013-11-06 11:48:53 -05:00
return true ;
}
bool
2015-02-06 16:38:51 -05:00
ValueObjectPrinter : : GetMostSpecializedValue ( )
2013-11-06 11:48:53 -05:00
{
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 ( ) )
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_use_dynamic = = eNoDynamicValues )
2013-11-06 11:48:53 -05:00
{
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
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_use_dynamic ! = eNoDynamicValues )
2013-11-06 11:48:53 -05:00
{
2015-12-30 06:55:28 -05:00
ValueObject * dynamic_value = m_orig_valobj - > GetDynamicValue ( m_options . m_use_dynamic ) . get ( ) ;
2013-11-06 11:48:53 -05:00
if ( dynamic_value )
m_valobj = dynamic_value ;
else
m_valobj = m_orig_valobj ;
}
else
m_valobj = m_orig_valobj ;
}
2015-02-06 16:38:51 -05:00
if ( m_valobj - > IsSynthetic ( ) )
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_use_synthetic = = false )
2015-02-06 16:38:51 -05:00
{
ValueObject * non_synthetic = m_valobj - > GetNonSyntheticValue ( ) . get ( ) ;
if ( non_synthetic )
m_valobj = non_synthetic ;
}
}
else
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_use_synthetic = = true )
2015-02-06 16:38:51 -05:00
{
ValueObject * synthetic = m_valobj - > GetSyntheticValue ( ) . get ( ) ;
if ( synthetic )
m_valobj = synthetic ;
}
}
2013-11-06 11:48:53 -05:00
}
2015-12-30 06:55:28 -05:00
m_compiler_type = m_valobj - > GetCompilerType ( ) ;
m_type_flags = m_compiler_type . GetTypeInfo ( ) ;
2013-11-06 11:48:53 -05:00
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 )
{
2015-12-30 06:55:28 -05:00
const char * root_valobj_name = m_options . m_root_valobj_name . empty ( ) ?
2013-11-06 11:48:53 -05:00
m_valobj - > GetName ( ) . AsCString ( ) :
2015-12-30 06:55:28 -05:00
m_options . m_root_valobj_name . c_str ( ) ;
2013-11-06 11:48:53 -05:00
return root_valobj_name ? root_valobj_name : if_fail ;
}
bool
ValueObjectPrinter : : ShouldPrintValueObject ( )
{
if ( m_should_print = = eLazyBoolCalculate )
2015-12-30 06:55:28 -05:00
m_should_print = ( m_options . m_flat_output = = false | | m_type_flags . Test ( eTypeHasValue ) ) ? eLazyBoolYes : eLazyBoolNo ;
2013-11-06 11:48:53 -05:00
return m_should_print = = eLazyBoolYes ;
}
bool
ValueObjectPrinter : : IsNil ( )
{
if ( m_is_nil = = eLazyBoolCalculate )
2015-12-30 06:55:28 -05:00
m_is_nil = m_valobj - > IsNilReference ( ) ? eLazyBoolYes : eLazyBoolNo ;
2013-11-06 11:48:53 -05:00
return m_is_nil = = eLazyBoolYes ;
}
2015-12-30 06:55:28 -05:00
bool
ValueObjectPrinter : : IsUninitialized ( )
{
if ( m_is_uninit = = eLazyBoolCalculate )
m_is_uninit = m_valobj - > IsUninitializedReference ( ) ? eLazyBoolYes : eLazyBoolNo ;
return m_is_uninit = = eLazyBoolYes ;
}
2013-11-06 11:48:53 -05:00
bool
ValueObjectPrinter : : IsPtr ( )
{
if ( m_is_ptr = = eLazyBoolCalculate )
2015-02-06 16:38:51 -05:00
m_is_ptr = m_type_flags . Test ( eTypeIsPointer ) ? eLazyBoolYes : eLazyBoolNo ;
2013-11-06 11:48:53 -05:00
return m_is_ptr = = eLazyBoolYes ;
}
bool
ValueObjectPrinter : : IsRef ( )
{
if ( m_is_ref = = eLazyBoolCalculate )
2015-02-06 16:38:51 -05:00
m_is_ref = m_type_flags . Test ( eTypeIsReference ) ? eLazyBoolYes : eLazyBoolNo ;
2013-11-06 11:48:53 -05:00
return m_is_ref = = eLazyBoolYes ;
}
bool
ValueObjectPrinter : : IsAggregate ( )
{
if ( m_is_aggregate = = eLazyBoolCalculate )
2015-02-06 16:38:51 -05:00
m_is_aggregate = m_type_flags . Test ( eTypeHasChildren ) ? eLazyBoolYes : eLazyBoolNo ;
2013-11-06 11:48:53 -05:00
return m_is_aggregate = = eLazyBoolYes ;
}
2015-12-30 06:55:28 -05:00
bool
ValueObjectPrinter : : IsInstancePointer ( )
{
// you need to do this check on the value's clang type
if ( m_is_instance_ptr = = eLazyBoolCalculate )
m_is_instance_ptr = ( m_valobj - > GetValue ( ) . GetCompilerType ( ) . GetTypeInfo ( ) & eTypeInstanceIsPointer ) ! = 0 ? eLazyBoolYes : eLazyBoolNo ;
if ( ( eLazyBoolYes = = m_is_instance_ptr ) & & m_valobj - > IsBaseClass ( ) )
m_is_instance_ptr = eLazyBoolNo ;
return m_is_instance_ptr = = eLazyBoolYes ;
}
2013-11-06 11:48:53 -05:00
bool
ValueObjectPrinter : : PrintLocationIfNeeded ( )
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_show_location )
2013-11-06 11:48:53 -05:00
{
m_stream - > Printf ( " %s: " , m_valobj - > GetLocationAsCString ( ) ) ;
return true ;
}
return false ;
}
2015-12-30 06:55:28 -05:00
void
ValueObjectPrinter : : PrintDecl ( )
2013-11-06 11:48:53 -05:00
{
bool show_type = true ;
// if we are at the root-level and been asked to hide the root's type, then hide it
2015-12-30 06:55:28 -05:00
if ( m_curr_depth = = 0 & & m_options . m_hide_root_type )
2013-11-06 11:48:53 -05:00
show_type = false ;
else
// otherwise decide according to the usual rules (asked to show types - always at the root level)
2015-12-30 06:55:28 -05:00
show_type = m_options . m_show_types | | ( m_curr_depth = = 0 & & ! m_options . m_flat_output ) ;
StreamString typeName ;
2013-11-06 11:48:53 -05:00
2015-12-30 06:55:28 -05:00
// always show the type at the root level if it is invalid
2013-11-06 11:48:53 -05:00
if ( show_type )
{
// Some ValueObjects don't have types (like registers sets). Only print
// the type if there is one to print
2015-02-06 16:38:51 -05:00
ConstString type_name ;
2015-12-30 06:55:28 -05:00
if ( m_compiler_type . IsValid ( ) )
{
if ( m_options . m_use_type_display_name )
type_name = m_valobj - > GetDisplayTypeName ( ) ;
else
type_name = m_valobj - > GetQualifiedTypeName ( ) ;
}
2014-11-25 16:00:58 -05:00
else
2015-12-30 06:55:28 -05:00
{
// only show an invalid type name if the user explicitly triggered show_type
if ( m_options . m_show_types )
type_name = ConstString ( " <invalid type> " ) ;
else
type_name . Clear ( ) ;
}
2015-02-06 16:38:51 -05:00
if ( type_name )
2015-12-30 06:55:28 -05:00
{
std : : string type_name_str ( type_name . GetCString ( ) ) ;
if ( m_options . m_hide_pointer_value )
{
for ( auto iter = type_name_str . find ( " * " ) ;
iter ! = std : : string : : npos ;
iter = type_name_str . find ( " * " ) )
{
type_name_str . erase ( iter , 2 ) ;
}
}
typeName . Printf ( " %s " , type_name_str . c_str ( ) ) ;
}
2013-11-06 11:48:53 -05:00
}
2015-12-30 06:55:28 -05:00
StreamString varName ;
if ( m_options . m_flat_output )
2013-11-06 11:48:53 -05:00
{
// If we are showing types, also qualify the C++ base classes
const bool qualify_cxx_base_classes = show_type ;
2015-12-30 06:55:28 -05:00
if ( ! m_options . m_hide_name )
2013-11-06 11:48:53 -05:00
{
2015-12-30 06:55:28 -05:00
m_valobj - > GetExpressionPath ( varName , qualify_cxx_base_classes ) ;
2013-11-06 11:48:53 -05:00
}
}
2015-12-30 06:55:28 -05:00
else if ( ! m_options . m_hide_name )
2013-11-06 11:48:53 -05:00
{
const char * name_cstr = GetRootNameForDisplay ( " " ) ;
2015-12-30 06:55:28 -05:00
varName . Printf ( " %s " , name_cstr ) ;
}
bool decl_printed = false ;
if ( ! m_options . m_decl_printing_helper )
{
// if the user didn't give us a custom helper, pick one based upon the language, either the one that this printer is bound to, or the preferred one for the ValueObject
lldb : : LanguageType lang_type = ( m_options . m_varformat_language = = lldb : : eLanguageTypeUnknown ) ? m_valobj - > GetPreferredDisplayLanguage ( ) : m_options . m_varformat_language ;
if ( Language * lang_plugin = Language : : FindPlugin ( lang_type ) )
{
m_options . m_decl_printing_helper = lang_plugin - > GetDeclPrintingHelper ( ) ;
}
}
if ( m_options . m_decl_printing_helper )
{
ConstString type_name_cstr ( typeName . GetData ( ) ) ;
ConstString var_name_cstr ( varName . GetData ( ) ) ;
StreamString dest_stream ;
if ( m_options . m_decl_printing_helper ( type_name_cstr ,
var_name_cstr ,
m_options ,
dest_stream ) )
{
decl_printed = true ;
m_stream - > Printf ( " %s " , dest_stream . GetData ( ) ) ;
}
}
// if the helper failed, or there is none, do a default thing
if ( ! decl_printed )
{
if ( typeName . GetSize ( ) )
m_stream - > Printf ( " (%s) " , typeName . GetData ( ) ) ;
if ( varName . GetSize ( ) )
m_stream - > Printf ( " %s = " , varName . GetData ( ) ) ;
else if ( ! m_options . m_hide_name )
m_stream - > Printf ( " = " ) ;
2013-11-06 11:48:53 -05:00
}
}
bool
ValueObjectPrinter : : CheckScopeIfNeeded ( )
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_scope_already_checked )
2013-11-06 11:48:53 -05:00
return true ;
return m_valobj - > IsInScope ( ) ;
}
TypeSummaryImpl *
2015-12-30 06:55:28 -05:00
ValueObjectPrinter : : GetSummaryFormatter ( bool null_if_omitted )
2013-11-06 11:48:53 -05:00
{
if ( m_summary_formatter . second = = false )
{
2015-12-30 06:55:28 -05:00
TypeSummaryImpl * entry = m_options . m_summary_sp ? m_options . m_summary_sp . get ( ) : m_valobj - > GetSummaryFormat ( ) . get ( ) ;
2013-11-06 11:48:53 -05:00
2015-12-30 06:55:28 -05:00
if ( m_options . m_omit_summary_depth > 0 )
2013-11-06 11:48:53 -05:00
entry = NULL ;
m_summary_formatter . first = entry ;
m_summary_formatter . second = true ;
}
2015-12-30 06:55:28 -05:00
if ( m_options . m_omit_summary_depth > 0 & & null_if_omitted )
return nullptr ;
2013-11-06 11:48:53 -05:00
return m_summary_formatter . first ;
}
2015-12-30 06:55:28 -05:00
static bool
IsPointerValue ( const CompilerType & type )
{
Flags type_flags ( type . GetTypeInfo ( ) ) ;
if ( type_flags . AnySet ( eTypeInstanceIsPointer | eTypeIsPointer ) )
return type_flags . AllClear ( eTypeIsBuiltIn ) ;
return false ;
}
2013-11-06 11:48:53 -05:00
void
ValueObjectPrinter : : GetValueSummaryError ( std : : string & value ,
std : : string & summary ,
std : : string & error )
{
2016-07-23 16:50:09 -04:00
lldb : : Format format = m_options . m_format ;
// if I am printing synthetized elements, apply the format to those elements only
if ( m_options . m_element_count > 0 )
m_valobj - > GetValueAsCString ( lldb : : eFormatDefault , value ) ;
else if ( format ! = eFormatDefault & & format ! = m_valobj - > GetFormat ( ) )
m_valobj - > GetValueAsCString ( format , value ) ;
2013-11-06 11:48:53 -05:00
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 " ) ;
2015-12-30 06:55:28 -05:00
else if ( IsUninitialized ( ) )
summary . assign ( " <uninitialized> " ) ;
else if ( m_options . m_omit_summary_depth = = 0 )
2013-11-06 11:48:53 -05:00
{
TypeSummaryImpl * entry = GetSummaryFormatter ( ) ;
if ( entry )
2015-12-30 06:55:28 -05:00
m_valobj - > GetSummaryAsCString ( entry , summary , m_options . m_varformat_language ) ;
2013-11-06 11:48:53 -05:00
else
{
2015-12-30 06:55:28 -05:00
const char * sum_cstr = m_valobj - > GetSummaryAsCString ( m_options . m_varformat_language ) ;
2013-11-06 11:48:53 -05:00
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 ( ) )
{
2015-12-30 06:55:28 -05:00
// we need to support scenarios in which it is actually fine for a value to have no type
// but - on the other hand - if we get an error *AND* have no type, we try to get out
// gracefully, since most often that combination means "could not resolve a type"
// and the default failure mode is quite ugly
if ( ! m_compiler_type . IsValid ( ) )
{
m_stream - > Printf ( " <could not resolve type> " ) ;
return false ;
}
2013-11-06 11:48:53 -05:00
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 ( ) ;
2015-12-30 06:55:28 -05:00
if ( ! IsNil ( ) & & ! IsUninitialized ( ) & & ! m_value . empty ( ) & & ( entry = = NULL | | ( entry - > DoesPrintValue ( m_valobj ) | | m_options . m_format ! = eFormatDefault ) | | m_summary . empty ( ) ) & & ! m_options . m_hide_value )
2013-11-06 11:48:53 -05:00
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_hide_pointer_value & & IsPointerValue ( m_valobj - > GetCompilerType ( ) ) ) { }
else
{
m_stream - > Printf ( " %s " , m_value . c_str ( ) ) ;
value_printed = true ;
}
2013-11-06 11:48:53 -05:00
}
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
2016-07-23 16:50:09 -04:00
if ( m_options . m_use_objc & & ! IsNil ( ) & & ! IsUninitialized ( ) & & ( m_options . m_element_count = = 0 ) )
2013-11-06 11:48:53 -05:00
{
2015-12-30 06:55:28 -05:00
if ( ! m_options . m_hide_value | | ! m_options . m_hide_name )
2013-11-06 11:48:53 -05:00
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 ;
}
2015-12-30 06:55:28 -05:00
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 ;
}
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 ;
}
return false ;
}
2013-11-06 11:48:53 -05:00
bool
ValueObjectPrinter : : ShouldPrintChildren ( bool is_failed_description ,
2015-12-30 06:55:28 -05:00
DumpValueObjectOptions : : PointerDepth & curr_ptr_depth )
2013-11-06 11:48:53 -05:00
{
const bool is_ref = IsRef ( ) ;
const bool is_ptr = IsPtr ( ) ;
2015-12-30 06:55:28 -05:00
const bool is_uninit = IsUninitialized ( ) ;
if ( is_uninit )
return false ;
2016-07-23 16:50:09 -04:00
// if the user has specified an element count, always print children
// as it is explicit user demand being honored
if ( m_options . m_element_count > 0 )
return true ;
2015-12-30 06:55:28 -05:00
TypeSummaryImpl * entry = GetSummaryFormatter ( ) ;
if ( m_options . m_use_objc )
return false ;
if ( is_failed_description | | m_curr_depth < m_options . m_max_depth )
2013-11-06 11:48:53 -05:00
{
// 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 ;
2015-12-30 06:55:28 -05:00
const bool is_root_level = m_curr_depth = = 0 ;
if ( is_ref & &
is_root_level )
2013-11-06 11:48:53 -05:00
{
// 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...
2015-12-30 06:55:28 -05:00
return true ;
2013-11-06 11:48:53 -05:00
}
2015-12-30 06:55:28 -05:00
return curr_ptr_depth . CanAllowExpansion ( false , entry , m_valobj , m_summary ) ;
2013-11-06 11:48:53 -05:00
}
2014-11-25 16:00:58 -05:00
return ( ! entry | | entry - > DoesPrintChildren ( m_valobj ) | | m_summary . empty ( ) ) ;
2013-11-06 11:48:53 -05:00
}
return false ;
}
2015-12-30 06:55:28 -05:00
bool
ValueObjectPrinter : : ShouldExpandEmptyAggregates ( )
{
TypeSummaryImpl * entry = GetSummaryFormatter ( ) ;
if ( ! entry )
return true ;
return entry - > DoesPrintEmptyAggregates ( ) ;
}
2013-11-06 11:48:53 -05:00
ValueObject *
ValueObjectPrinter : : GetValueObjectForChildrenGeneration ( )
{
2015-02-06 16:38:51 -05:00
return m_valobj ;
2013-11-06 11:48:53 -05:00
}
void
ValueObjectPrinter : : PrintChildrenPreamble ( )
{
2015-12-30 06:55:28 -05:00
if ( m_options . m_flat_output )
2013-11-06 11:48:53 -05:00
{
if ( ShouldPrintValueObject ( ) )
m_stream - > EOL ( ) ;
}
else
{
if ( ShouldPrintValueObject ( ) )
m_stream - > PutCString ( IsRef ( ) ? " : { \n " : " { \n " ) ;
m_stream - > IndentMore ( ) ;
}
}
void
ValueObjectPrinter : : PrintChild ( ValueObjectSP child_sp ,
2015-12-30 06:55:28 -05:00
const DumpValueObjectOptions : : PointerDepth & curr_ptr_depth )
2013-11-06 11:48:53 -05:00
{
2016-07-23 16:50:09 -04:00
const uint32_t consumed_depth = ( m_options . m_element_count = = 0 ) ? 1 : 0 ;
const bool does_consume_ptr_depth = ( ( IsPtr ( ) & & m_options . m_element_count = = 0 ) | | IsRef ( ) ) ;
2015-12-30 06:55:28 -05:00
DumpValueObjectOptions child_options ( m_options ) ;
child_options . SetFormat ( m_options . m_format ) . SetSummary ( ) . SetRootValueObjectName ( ) ;
child_options . SetScopeChecked ( true ) . SetHideName ( m_options . m_hide_name ) . SetHideValue ( m_options . m_hide_value )
2016-07-23 16:50:09 -04:00
. SetOmitSummaryDepth ( child_options . m_omit_summary_depth > 1 ? child_options . m_omit_summary_depth - consumed_depth : 0 )
. SetElementCount ( 0 ) ;
2015-12-30 06:55:28 -05:00
2013-11-06 11:48:53 -05:00
if ( child_sp . get ( ) )
{
ValueObjectPrinter child_printer ( child_sp . get ( ) ,
m_stream ,
child_options ,
2016-07-23 16:50:09 -04:00
does_consume_ptr_depth ? - - curr_ptr_depth : curr_ptr_depth ,
m_curr_depth + consumed_depth ,
2015-12-30 06:55:28 -05:00
m_printed_instance_pointers ) ;
2013-11-06 11:48:53 -05:00
child_printer . PrintValueObject ( ) ;
}
}
uint32_t
ValueObjectPrinter : : GetMaxNumChildrenToPrint ( bool & print_dotdotdot )
{
ValueObject * synth_m_valobj = GetValueObjectForChildrenGeneration ( ) ;
2016-07-23 16:50:09 -04:00
if ( m_options . m_element_count > 0 )
return m_options . m_element_count ;
2013-11-06 11:48:53 -05:00
size_t num_children = synth_m_valobj - > GetNumChildren ( ) ;
print_dotdotdot = false ;
if ( num_children )
{
const size_t max_num_children = m_valobj - > GetTargetSP ( ) - > GetMaximumNumberOfChildrenToDisplay ( ) ;
2015-12-30 06:55:28 -05:00
if ( num_children > max_num_children & & ! m_options . m_ignore_cap )
2013-11-06 11:48:53 -05:00
{
print_dotdotdot = true ;
return max_num_children ;
}
}
return num_children ;
}
void
ValueObjectPrinter : : PrintChildrenPostamble ( bool print_dotdotdot )
{
2015-12-30 06:55:28 -05:00
if ( ! m_options . m_flat_output )
2013-11-06 11:48:53 -05:00
{
if ( print_dotdotdot )
{
m_valobj - > GetTargetSP ( ) - > GetDebugger ( ) . GetCommandInterpreter ( ) . ChildrenTruncated ( ) ;
m_stream - > Indent ( " ... \n " ) ;
}
m_stream - > IndentLess ( ) ;
m_stream - > Indent ( " } \n " ) ;
}
}
2015-12-30 06:55:28 -05:00
bool
ValueObjectPrinter : : ShouldPrintEmptyBrackets ( bool value_printed ,
bool summary_printed )
{
ValueObject * synth_m_valobj = GetValueObjectForChildrenGeneration ( ) ;
if ( ! IsAggregate ( ) )
return false ;
if ( m_options . m_reveal_empty_aggregates = = false )
{
if ( value_printed | | summary_printed )
return false ;
}
if ( synth_m_valobj - > MightHaveChildren ( ) )
return true ;
if ( m_val_summary_ok )
return false ;
return true ;
}
2016-07-23 16:50:09 -04:00
ValueObjectSP
ValueObjectPrinter : : GenerateChild ( ValueObject * synth_valobj , size_t idx )
{
if ( m_options . m_element_count > 0 )
{
// if generating pointer-as-array children, use GetSyntheticArrayMember
return synth_valobj - > GetSyntheticArrayMember ( idx , true ) ;
}
else
{
// otherwise, do the usual thing
return synth_valobj - > GetChildAtIndex ( idx , true ) ;
}
}
2013-11-06 11:48:53 -05:00
void
2015-12-30 06:55:28 -05:00
ValueObjectPrinter : : PrintChildren ( bool value_printed ,
bool summary_printed ,
const DumpValueObjectOptions : : PointerDepth & curr_ptr_depth )
2013-11-06 11:48:53 -05:00
{
ValueObject * synth_m_valobj = GetValueObjectForChildrenGeneration ( ) ;
bool print_dotdotdot = false ;
size_t num_children = GetMaxNumChildrenToPrint ( print_dotdotdot ) ;
if ( num_children )
{
2015-12-30 06:55:28 -05:00
bool any_children_printed = false ;
2013-11-06 11:48:53 -05:00
for ( size_t idx = 0 ; idx < num_children ; + + idx )
{
2016-07-23 16:50:09 -04:00
if ( ValueObjectSP child_sp = GenerateChild ( synth_m_valobj , idx ) )
2015-12-30 06:55:28 -05:00
{
if ( ! any_children_printed )
{
PrintChildrenPreamble ( ) ;
any_children_printed = true ;
}
PrintChild ( child_sp , curr_ptr_depth ) ;
}
2013-11-06 11:48:53 -05:00
}
2015-12-30 06:55:28 -05:00
if ( any_children_printed )
PrintChildrenPostamble ( print_dotdotdot ) ;
else
{
if ( ShouldPrintEmptyBrackets ( value_printed , summary_printed ) )
{
if ( ShouldPrintValueObject ( ) )
m_stream - > PutCString ( " {} \n " ) ;
else
m_stream - > EOL ( ) ;
}
else
m_stream - > EOL ( ) ;
}
2013-11-06 11:48:53 -05:00
}
2015-12-30 06:55:28 -05:00
else if ( ShouldPrintEmptyBrackets ( value_printed , summary_printed ) )
2013-11-06 11:48:53 -05:00
{
// Aggregate, no children...
if ( ShouldPrintValueObject ( ) )
2015-02-06 16:38:51 -05:00
{
// if it has a synthetic value, then don't print {}, the synthetic children are probably only being used to vend a value
2015-12-30 06:55:28 -05:00
if ( m_valobj - > DoesProvideSyntheticValue ( ) | | ! ShouldExpandEmptyAggregates ( ) )
2015-02-06 16:38:51 -05:00
m_stream - > PutCString ( " \n " ) ;
else
m_stream - > PutCString ( " {} \n " ) ;
}
2013-11-06 11:48:53 -05:00
}
else
{
if ( ShouldPrintValueObject ( ) )
m_stream - > EOL ( ) ;
}
}
bool
ValueObjectPrinter : : PrintChildrenOneLiner ( bool hide_names )
{
2015-02-06 16:38:51 -05:00
if ( ! GetMostSpecializedValue ( ) | | m_valobj = = nullptr )
2013-11-06 11:48:53 -05:00
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 ) ) ;
2015-02-06 16:38:51 -05:00
if ( child_sp )
2015-12-30 06:55:28 -05:00
child_sp = child_sp - > GetQualifiedRepresentationIfAvailable ( m_options . m_use_dynamic , m_options . m_use_synthetic ) ;
2013-11-06 11:48:53 -05:00
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 ,
2015-12-30 06:55:28 -05:00
m_options . m_format ,
2013-11-06 11:48:53 -05:00
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 ) ;
2015-12-30 06:55:28 -05:00
auto curr_ptr_depth = m_ptr_depth ;
2013-11-06 11:48:53 -05:00
bool print_children = ShouldPrintChildren ( is_failed_description , curr_ptr_depth ) ;
2015-12-30 06:55:28 -05:00
bool print_oneline = ( curr_ptr_depth . CanAllowExpansion ( ) | |
m_options . m_show_types | |
! m_options . m_allow_oneliner_mode | |
m_options . m_flat_output | |
2016-07-23 16:50:09 -04:00
( m_options . m_element_count > 0 ) | |
2015-12-30 06:55:28 -05:00
m_options . m_show_location ) ? false : DataVisualization : : ShouldPrintAsOneLiner ( * m_valobj ) ;
bool is_instance_ptr = IsInstancePointer ( ) ;
uint64_t instance_ptr_value = LLDB_INVALID_ADDRESS ;
if ( print_children & & is_instance_ptr )
{
instance_ptr_value = m_valobj - > GetValueAsUnsigned ( 0 ) ;
if ( m_printed_instance_pointers - > count ( instance_ptr_value ) )
{
// we already printed this instance-is-pointer thing, so don't expand it
m_stream - > PutCString ( " {...} \n " ) ;
// we're done here - get out fast
return ;
}
else
m_printed_instance_pointers - > emplace ( instance_ptr_value ) ; // remember this guy for future reference
}
2013-11-06 11:48:53 -05:00
if ( print_children )
{
if ( print_oneline )
{
m_stream - > PutChar ( ' ' ) ;
PrintChildrenOneLiner ( false ) ;
m_stream - > EOL ( ) ;
}
else
2015-12-30 06:55:28 -05:00
PrintChildren ( value_printed , summary_printed , curr_ptr_depth ) ;
2013-11-06 11:48:53 -05:00
}
2015-12-30 06:55:28 -05:00
else if ( m_curr_depth > = m_options . m_max_depth & & IsAggregate ( ) & & ShouldPrintValueObject ( ) )
2013-11-06 11:48:53 -05:00
{
2015-12-30 06:55:28 -05:00
m_stream - > PutCString ( " {...} \n " ) ;
2013-11-06 11:48:53 -05:00
}
else
m_stream - > EOL ( ) ;
}
2015-02-06 16:38:51 -05:00
bool
ValueObjectPrinter : : ShouldPrintValidation ( )
{
2015-12-30 06:55:28 -05:00
return m_options . m_run_validator ;
2015-02-06 16:38:51 -05:00
}
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 ;
}