diff options
author | Enrico Granata <egranata@apple.com> | 2013-09-30 19:11:51 +0000 |
---|---|---|
committer | Enrico Granata <egranata@apple.com> | 2013-09-30 19:11:51 +0000 |
commit | 4d93b8cdf3f15bf95e6c1522bac14b660b1d5791 (patch) | |
tree | 171686bdcc54855cc856713986a0aa7fa51b7b3e | |
parent | 9515b31096e3ef3f00acb9cbd8f4e6f4770005ff (diff) | |
download | bcm5719-llvm-4d93b8cdf3f15bf95e6c1522bac14b660b1d5791.tar.gz bcm5719-llvm-4d93b8cdf3f15bf95e6c1522bac14b660b1d5791.zip |
<rdar://problem/14393032>
DumpValueObject() 2.0
This checkin restores pre-Xcode5 functionality to the "po" (expr -O) command:
- expr now has a new --description-verbosity (-v) argument, which takes either compact or full as a value (-v is the same as -vfull)
When the full mode is on, "po" will show the extended output with type name, persistent variable name and value, as in
(lldb) expr -O -v -- foo
(id) $0 = 0x000000010010baf0 {
1 = 2;
2 = 3;
}
When -v is omitted, or -vcompact is passed, the Xcode5-style output will be shown, as in
(lldb) expr -O -- foo
{
1 = 2;
2 = 3;
}
- for a non-ObjectiveC object, LLDB will still try to retrieve a summary and/or value to display
(lldb) po 5
5
-v also works in this mode
(lldb) expr -O -vfull -- 5
(int) $4 = 5
On top of that, this is a major refactoring of the ValueObject printing code. The functionality is now factored into a ValueObjectPrinter class for easier maintenance in the future
DumpValueObject() was turned into an instance method ValueObject::Dump() which simply calls through to the printer code, Dump_Impl has been removed
Test case to follow
llvm-svn: 191694
20 files changed, 1002 insertions, 576 deletions
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index dd704f15438..b304563221e 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -216,229 +216,6 @@ public: } }; - - struct DumpValueObjectOptions - { - uint32_t m_max_ptr_depth; - uint32_t m_max_depth; - bool m_show_types; - bool m_show_location; - bool m_use_objc; - lldb::DynamicValueType m_use_dynamic; - bool m_use_synthetic; - bool m_scope_already_checked; - bool m_flat_output; - uint32_t m_omit_summary_depth; - bool m_ignore_cap; - lldb::Format m_format; - lldb::TypeSummaryImplSP m_summary_sp; - std::string m_root_valobj_name; - bool m_hide_root_type; - bool m_hide_name; - bool m_hide_value; - - DumpValueObjectOptions() : - m_max_ptr_depth(0), - m_max_depth(UINT32_MAX), - m_show_types(false), - m_show_location(false), - m_use_objc(false), - m_use_dynamic(lldb::eNoDynamicValues), - m_use_synthetic(true), - m_scope_already_checked(false), - m_flat_output(false), - m_omit_summary_depth(0), - m_ignore_cap(false), - m_format (lldb::eFormatDefault), - m_summary_sp(), - m_root_valobj_name(), - m_hide_root_type(false), // provide a special compact display for "po" - m_hide_name(false), // provide a special compact display for "po" - m_hide_value(false) // provide a special compact display for "po" - {} - - static const DumpValueObjectOptions - DefaultOptions() - { - static DumpValueObjectOptions g_default_options; - - return g_default_options; - } - - DumpValueObjectOptions (const DumpValueObjectOptions& rhs) : - m_max_ptr_depth(rhs.m_max_ptr_depth), - m_max_depth(rhs.m_max_depth), - m_show_types(rhs.m_show_types), - m_show_location(rhs.m_show_location), - m_use_objc(rhs.m_use_objc), - m_use_dynamic(rhs.m_use_dynamic), - m_use_synthetic(rhs.m_use_synthetic), - m_scope_already_checked(rhs.m_scope_already_checked), - m_flat_output(rhs.m_flat_output), - m_omit_summary_depth(rhs.m_omit_summary_depth), - m_ignore_cap(rhs.m_ignore_cap), - m_format(rhs.m_format), - m_summary_sp(rhs.m_summary_sp), - m_root_valobj_name(rhs.m_root_valobj_name), - m_hide_root_type(rhs.m_hide_root_type), - m_hide_name(rhs.m_hide_name), - m_hide_value(rhs.m_hide_value) - {} - - DumpValueObjectOptions& - SetMaximumPointerDepth(uint32_t depth = 0) - { - m_max_ptr_depth = depth; - return *this; - } - - DumpValueObjectOptions& - SetMaximumDepth(uint32_t depth = 0) - { - m_max_depth = depth; - return *this; - } - - DumpValueObjectOptions& - SetShowTypes(bool show = false) - { - m_show_types = show; - return *this; - } - - DumpValueObjectOptions& - SetShowLocation(bool show = false) - { - m_show_location = show; - return *this; - } - - DumpValueObjectOptions& - SetUseObjectiveC(bool use = false) - { - m_use_objc = use; - return *this; - } - - DumpValueObjectOptions& - SetShowSummary(bool show = true) - { - if (show == false) - SetOmitSummaryDepth(UINT32_MAX); - else - SetOmitSummaryDepth(0); - return *this; - } - - DumpValueObjectOptions& - SetUseDynamicType(lldb::DynamicValueType dyn = lldb::eNoDynamicValues) - { - m_use_dynamic = dyn; - return *this; - } - - DumpValueObjectOptions& - SetUseSyntheticValue(bool use_synthetic = true) - { - m_use_synthetic = use_synthetic; - return *this; - } - - DumpValueObjectOptions& - SetScopeChecked(bool check = true) - { - m_scope_already_checked = check; - return *this; - } - - DumpValueObjectOptions& - SetFlatOutput(bool flat = false) - { - m_flat_output = flat; - return *this; - } - - DumpValueObjectOptions& - SetOmitSummaryDepth(uint32_t depth = 0) - { - m_omit_summary_depth = depth; - return *this; - } - - DumpValueObjectOptions& - SetIgnoreCap(bool ignore = false) - { - m_ignore_cap = ignore; - return *this; - } - - DumpValueObjectOptions& - SetRawDisplay(bool raw = false) - { - if (raw) - { - SetUseSyntheticValue(false); - SetOmitSummaryDepth(UINT32_MAX); - SetIgnoreCap(true); - SetHideName(false); - SetHideValue(false); - } - else - { - SetUseSyntheticValue(true); - SetOmitSummaryDepth(0); - SetIgnoreCap(false); - SetHideName(false); - SetHideValue(false); - } - return *this; - } - - DumpValueObjectOptions& - SetFormat (lldb::Format format = lldb::eFormatDefault) - { - m_format = format; - return *this; - } - - DumpValueObjectOptions& - SetSummary (lldb::TypeSummaryImplSP summary = lldb::TypeSummaryImplSP()) - { - m_summary_sp = summary; - return *this; - } - - DumpValueObjectOptions& - SetRootValueObjectName (const char* name = NULL) - { - if (name) - m_root_valobj_name.assign(name); - else - m_root_valobj_name.clear(); - return *this; - } - - DumpValueObjectOptions& - SetHideRootType (bool hide_root_type = false) - { - m_hide_root_type = hide_root_type; - return *this; - } - - DumpValueObjectOptions& - SetHideName (bool hide_name = false) - { - m_hide_name = hide_name; - return *this; - } - - DumpValueObjectOptions& - SetHideValue (bool hide_value = false) - { - m_hide_value = hide_value; - return *this; - } - }; class EvaluationPoint { @@ -953,13 +730,12 @@ public: virtual SymbolContextScope * GetSymbolContextScope(); - static void - DumpValueObject (Stream &s, - ValueObject *valobj); - static void - DumpValueObject (Stream &s, - ValueObject *valobj, - const DumpValueObjectOptions& options); + void + Dump (Stream &s); + + void + Dump (Stream &s, + const DumpValueObjectOptions& options); static lldb::ValueObjectSP CreateValueObjectFromExpression (const char* name, @@ -978,13 +754,11 @@ public: const ExecutionContext& exe_ctx, ClangASTType type); - static void - LogValueObject (Log *log, - ValueObject *valobj); + void + LogValueObject (Log *log); - static void + void LogValueObject (Log *log, - ValueObject *valobj, const DumpValueObjectOptions& options); diff --git a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h new file mode 100644 index 00000000000..7b149a51c17 --- /dev/null +++ b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h @@ -0,0 +1,377 @@ +//===-- ValueObjectPrinter.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_ValueObjectPrinter_h_ +#define lldb_ValueObjectPrinter_h_ + +// C Includes +// C++ Includes + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/lldb-public.h" + +#include "lldb/Core/Stream.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/TypeSummary.h" + +namespace lldb_private { + +struct DumpValueObjectOptions +{ + uint32_t m_max_ptr_depth; + uint32_t m_max_depth; + bool m_show_types; + bool m_show_location; + bool m_use_objc; + lldb::DynamicValueType m_use_dynamic; + bool m_use_synthetic; + bool m_scope_already_checked; + bool m_flat_output; + uint32_t m_omit_summary_depth; + bool m_ignore_cap; + lldb::Format m_format; + lldb::TypeSummaryImplSP m_summary_sp; + std::string m_root_valobj_name; + bool m_hide_root_type; + bool m_hide_name; + bool m_hide_value; + + DumpValueObjectOptions() : + m_max_ptr_depth(0), + m_max_depth(UINT32_MAX), + m_show_types(false), + m_show_location(false), + m_use_objc(false), + m_use_dynamic(lldb::eNoDynamicValues), + m_use_synthetic(true), + m_scope_already_checked(false), + m_flat_output(false), + m_omit_summary_depth(0), + m_ignore_cap(false), + m_format (lldb::eFormatDefault), + m_summary_sp(), + m_root_valobj_name(), + m_hide_root_type(false), // provide a special compact display for "po" + m_hide_name(false), // provide a special compact display for "po" + m_hide_value(false) // provide a special compact display for "po" + {} + + static const DumpValueObjectOptions + DefaultOptions() + { + static DumpValueObjectOptions g_default_options; + + return g_default_options; + } + + DumpValueObjectOptions (const DumpValueObjectOptions& rhs) : + m_max_ptr_depth(rhs.m_max_ptr_depth), + m_max_depth(rhs.m_max_depth), + m_show_types(rhs.m_show_types), + m_show_location(rhs.m_show_location), + m_use_objc(rhs.m_use_objc), + m_use_dynamic(rhs.m_use_dynamic), + m_use_synthetic(rhs.m_use_synthetic), + m_scope_already_checked(rhs.m_scope_already_checked), + m_flat_output(rhs.m_flat_output), + m_omit_summary_depth(rhs.m_omit_summary_depth), + m_ignore_cap(rhs.m_ignore_cap), + m_format(rhs.m_format), + m_summary_sp(rhs.m_summary_sp), + m_root_valobj_name(rhs.m_root_valobj_name), + m_hide_root_type(rhs.m_hide_root_type), + m_hide_name(rhs.m_hide_name), + m_hide_value(rhs.m_hide_value) + {} + + DumpValueObjectOptions& + SetMaximumPointerDepth(uint32_t depth = 0) + { + m_max_ptr_depth = depth; + return *this; + } + + DumpValueObjectOptions& + SetMaximumDepth(uint32_t depth = 0) + { + m_max_depth = depth; + return *this; + } + + DumpValueObjectOptions& + SetShowTypes(bool show = false) + { + m_show_types = show; + return *this; + } + + DumpValueObjectOptions& + SetShowLocation(bool show = false) + { + m_show_location = show; + return *this; + } + + DumpValueObjectOptions& + SetUseObjectiveC(bool use = false) + { + m_use_objc = use; + return *this; + } + + DumpValueObjectOptions& + SetShowSummary(bool show = true) + { + if (show == false) + SetOmitSummaryDepth(UINT32_MAX); + else + SetOmitSummaryDepth(0); + return *this; + } + + DumpValueObjectOptions& + SetUseDynamicType(lldb::DynamicValueType dyn = lldb::eNoDynamicValues) + { + m_use_dynamic = dyn; + return *this; + } + + DumpValueObjectOptions& + SetUseSyntheticValue(bool use_synthetic = true) + { + m_use_synthetic = use_synthetic; + return *this; + } + + DumpValueObjectOptions& + SetScopeChecked(bool check = true) + { + m_scope_already_checked = check; + return *this; + } + + DumpValueObjectOptions& + SetFlatOutput(bool flat = false) + { + m_flat_output = flat; + return *this; + } + + DumpValueObjectOptions& + SetOmitSummaryDepth(uint32_t depth = 0) + { + m_omit_summary_depth = depth; + return *this; + } + + DumpValueObjectOptions& + SetIgnoreCap(bool ignore = false) + { + m_ignore_cap = ignore; + return *this; + } + + DumpValueObjectOptions& + SetRawDisplay(bool raw = false) + { + if (raw) + { + SetUseSyntheticValue(false); + SetOmitSummaryDepth(UINT32_MAX); + SetIgnoreCap(true); + SetHideName(false); + SetHideValue(false); + } + else + { + SetUseSyntheticValue(true); + SetOmitSummaryDepth(0); + SetIgnoreCap(false); + SetHideName(false); + SetHideValue(false); + } + return *this; + } + + DumpValueObjectOptions& + SetFormat (lldb::Format format = lldb::eFormatDefault) + { + m_format = format; + return *this; + } + + DumpValueObjectOptions& + SetSummary (lldb::TypeSummaryImplSP summary = lldb::TypeSummaryImplSP()) + { + m_summary_sp = summary; + return *this; + } + + DumpValueObjectOptions& + SetRootValueObjectName (const char* name = NULL) + { + if (name) + m_root_valobj_name.assign(name); + else + m_root_valobj_name.clear(); + return *this; + } + + DumpValueObjectOptions& + SetHideRootType (bool hide_root_type = false) + { + m_hide_root_type = hide_root_type; + return *this; + } + + DumpValueObjectOptions& + SetHideName (bool hide_name = false) + { + m_hide_name = hide_name; + return *this; + } + + DumpValueObjectOptions& + SetHideValue (bool hide_value = false) + { + m_hide_value = hide_value; + return *this; + } +}; + +class ValueObjectPrinter +{ +public: + + ValueObjectPrinter (ValueObject* valobj, + Stream* s, + const DumpValueObjectOptions& options); + + ~ValueObjectPrinter () {} + + bool + PrintValueObject (); + +protected: + + // only this class (and subclasses, if any) should ever be concerned with + // the depth mechanism + ValueObjectPrinter (ValueObject* valobj, + Stream* s, + const DumpValueObjectOptions& options, + uint32_t ptr_depth, + uint32_t curr_depth); + + bool + GetDynamicValueIfNeeded (); + + const char* + GetDescriptionForDisplay (); + + const char* + GetRootNameForDisplay (const char* if_fail = nullptr); + + bool + ShouldPrintValueObject (); + + bool + IsNil (); + + bool + IsPtr (); + + bool + IsRef (); + + bool + IsAggregate (); + + bool + PrintLocationIfNeeded (); + + bool + PrintTypeIfNeeded (); + + bool + PrintNameIfNeeded (bool show_type); + + bool + CheckScopeIfNeeded (); + + TypeSummaryImpl* + GetSummaryFormatter (); + + void + GetValueSummaryError (std::string& value, + std::string& summary, + std::string& error); + + bool + PrintValueAndSummaryIfNeeded (bool& value_printed, + bool& summary_printed); + + bool + PrintObjectDescriptionIfNeeded (bool value_printed, + bool summary_printed); + + bool + ShouldPrintChildren (bool is_failed_description, + uint32_t& curr_ptr_depth); + + ValueObject* + GetValueObjectForChildrenGeneration (); + + void + PrintChildrenPreamble (); + + void + PrintChildrenPostamble (bool print_dotdotdot); + + void + PrintChild (lldb::ValueObjectSP child_sp, + uint32_t curr_ptr_depth); + + uint32_t + GetMaxNumChildrenToPrint (bool& print_dotdotdot); + + void + PrintChildren (uint32_t curr_ptr_depth); + + void + PrintChildrenIfNeeded (bool value_printed, + bool summary_printed); + +private: + + ValueObject *m_orig_valobj; + ValueObject *m_valobj; + Stream *m_stream; + DumpValueObjectOptions options; + Flags m_type_flags; + ClangASTType m_clang_type; + uint32_t m_ptr_depth; + uint32_t m_curr_depth; + LazyBool m_should_print; + LazyBool m_is_nil; + LazyBool m_is_ptr; + LazyBool m_is_ref; + LazyBool m_is_aggregate; + std::pair<TypeSummaryImpl*,bool> m_summary_formatter; + std::string m_value; + std::string m_summary; + std::string m_error; + + DISALLOW_COPY_AND_ASSIGN(ValueObjectPrinter); +}; + +} // namespace lldb_private + +#endif // lldb_ValueObjectPrinter_h_ diff --git a/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h b/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h index da05e127d5d..c09528f9f51 100644 --- a/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h +++ b/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h @@ -62,8 +62,8 @@ public: ignore_cap == true; } - ValueObject::DumpValueObjectOptions - GetAsDumpOptions (bool objc_is_compact = false, + DumpValueObjectOptions + GetAsDumpOptions (LanguageRuntimeDescriptionDisplayVerbosity lang_descr_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull, lldb::Format format = lldb::eFormatDefault, lldb::TypeSummaryImplSP summary_sp = lldb::TypeSummaryImplSP()); diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 9ef342e3e98..40b77ed4b91 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -380,6 +380,7 @@ namespace lldb { eArgTypeClassName, eArgTypeCommandName, eArgTypeCount, + eArgTypeDescriptionVerbosity, eArgTypeDirectoryName, eArgTypeDisassemblyFlavor, eArgTypeEndAddress, diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index d8bc42c9212..08d1f2122bf 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -79,6 +79,7 @@ class DataExtractor; class Debugger; class Declaration; class Disassembler; +class DumpValueObjectOptions; class DynamicLibrary; class DynamicLoader; class EmulateInstruction; @@ -248,6 +249,7 @@ class ValueObjectConstResult; class ValueObjectConstResultChild; class ValueObjectConstResultImpl; class ValueObjectList; +class ValueObjectPrinter; class Variable; class VariableList; class Watchpoint; diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index 9ee8f114a4c..62a3e49184f 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -229,6 +229,14 @@ typedef enum ScriptedCommandSynchronicity eScriptedCommandSynchronicityCurrentValue // use whatever the current synchronicity is } ScriptedCommandSynchronicity; +//---------------------------------------------------------------------- +// Verbosity mode of "po" output +//---------------------------------------------------------------------- +typedef enum LanguageRuntimeDescriptionDisplayVerbosity +{ + eLanguageRuntimeDescriptionDisplayVerbosityCompact, // only print the description string, if any + eLanguageRuntimeDescriptionDisplayVerbosityFull, // print the full-blown output +} LanguageRuntimeDescriptionDisplayVerbosity; //---------------------------------------------------------------------- // Loading modules from memory diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 17824291df4..e19ace17e26 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -531,6 +531,7 @@ 944372DD171F6B4300E57C32 /* RegisterContextDummy.h in Headers */ = {isa = PBXBuildFile; fileRef = 944372DB171F6B4300E57C32 /* RegisterContextDummy.h */; }; 9443B122140C18C40013457C /* SBData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9443B121140C18C10013457C /* SBData.cpp */; }; 9443B123140C26AB0013457C /* SBData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9443B120140C18A90013457C /* SBData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 945215DF17F639EE00521C0B /* ValueObjectPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945215DE17F639EE00521C0B /* ValueObjectPrinter.cpp */; }; 9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9452573916262D0200325455 /* SBDeclaration.cpp */; }; 9456F2241616671900656F91 /* DynamicLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9456F2211616644B00656F91 /* DynamicLibrary.cpp */; }; 945759671534941F005A9070 /* PlatformPOSIX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945759651534941F005A9070 /* PlatformPOSIX.cpp */; }; @@ -1575,6 +1576,8 @@ 9443B120140C18A90013457C /* SBData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBData.h; path = include/lldb/API/SBData.h; sourceTree = "<group>"; }; 9443B121140C18C10013457C /* SBData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBData.cpp; path = source/API/SBData.cpp; sourceTree = "<group>"; }; 944DC3481774C99000D7D884 /* python-swigsafecast.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-swigsafecast.swig"; sourceTree = "<group>"; }; + 945215DD17F639E600521C0B /* ValueObjectPrinter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectPrinter.h; path = include/lldb/DataFormatters/ValueObjectPrinter.h; sourceTree = "<group>"; }; + 945215DE17F639EE00521C0B /* ValueObjectPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectPrinter.cpp; path = source/DataFormatters/ValueObjectPrinter.cpp; sourceTree = "<group>"; }; 9452573616262CD000325455 /* SBDeclaration.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBDeclaration.i; sourceTree = "<group>"; }; 9452573816262CEF00325455 /* SBDeclaration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBDeclaration.h; path = include/lldb/API/SBDeclaration.h; sourceTree = "<group>"; }; 9452573916262D0200325455 /* SBDeclaration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBDeclaration.cpp; path = source/API/SBDeclaration.cpp; sourceTree = "<group>"; }; @@ -3465,6 +3468,8 @@ 94CB256E16B0A4260059775D /* TypeSummary.cpp */, 94CB256C16B0A4040059775D /* TypeSynthetic.h */, 94CB256F16B0A4270059775D /* TypeSynthetic.cpp */, + 945215DD17F639E600521C0B /* ValueObjectPrinter.h */, + 945215DE17F639EE00521C0B /* ValueObjectPrinter.cpp */, ); name = DataFormatters; sourceTree = "<group>"; @@ -4305,6 +4310,7 @@ 945E8D80152F6AB40019BCCD /* StreamGDBRemote.cpp in Sources */, 945759671534941F005A9070 /* PlatformPOSIX.cpp in Sources */, 26B1EFAE154638AF00E2DAC7 /* DWARFDeclContext.cpp in Sources */, + 945215DF17F639EE00521C0B /* ValueObjectPrinter.cpp in Sources */, 260CC64815D0440D002BF2E0 /* OptionValueArgs.cpp in Sources */, 260CC64915D0440D002BF2E0 /* OptionValueArray.cpp in Sources */, 260CC64A15D0440D002BF2E0 /* OptionValueBoolean.cpp in Sources */, diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index f13b6722d99..c860876fd12 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -1394,9 +1394,7 @@ SBValue::GetDescription (SBStream &description) ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); if (value_sp) - { - ValueObject::DumpValueObject (strm, value_sp.get()); - } + value_sp->Dump(strm); else strm.PutCString ("No value"); diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 7186b9a7cb4..8b04da600f4 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/Value.h" #include "lldb/Core/InputReader.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Expression/ClangExpressionVariable.h" #include "lldb/Expression/ClangUserExpression.h" #include "lldb/Expression/ClangFunction.h" @@ -49,6 +50,13 @@ CommandObjectExpression::CommandOptions::~CommandOptions () { } +static OptionEnumValueElement g_description_verbosity_type[] = +{ + { eLanguageRuntimeDescriptionDisplayVerbosityCompact, "compact", "Only show the description string"}, + { eLanguageRuntimeDescriptionDisplayVerbosityFull, "full", "Show the full output, including persistent variable's name and type"}, + { 0, NULL, NULL } +}; + OptionDefinition CommandObjectExpression::CommandOptions::g_option_table[] = { @@ -56,6 +64,7 @@ CommandObjectExpression::CommandOptions::g_option_table[] = { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"}, { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."}, { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."}, + { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."}, }; @@ -127,6 +136,18 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); break; } + + case 'v': + if (!option_arg) + { + m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull; + break; + } + m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); + if (!error.Success()) + error.SetErrorStringWithFormat ("unrecognized value for description-verbosity '%s'", option_arg); + break; + default: error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); break; @@ -153,6 +174,7 @@ CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpret show_summary = true; try_all_threads = true; timeout = 0; + m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact; } const OptionDefinition* @@ -357,11 +379,10 @@ CommandObjectExpression::EvaluateExpression if (format != eFormatDefault) result_valobj_sp->SetFormat (format); - ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(true,format)); + DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format)); - ValueObject::DumpValueObject (*(output_stream), - result_valobj_sp.get(), // Variable object to dump - options); + result_valobj_sp->Dump(*output_stream,options); + if (result) result->SetStatus (eReturnStatusSuccessFinishResult); } diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index 3964f2d423e..a62a21287c2 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -57,6 +57,7 @@ public: bool show_summary; uint32_t timeout; bool try_all_threads; + LanguageRuntimeDescriptionDisplayVerbosity m_verbosity; }; CommandObjectExpression (CommandInterpreter &interpreter); diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index 202d62e6009..2e852d0bb76 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -25,6 +25,7 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -400,7 +401,7 @@ protected: else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) summary_format_sp.reset(new StringSummaryFormat(TypeSummaryImpl::Flags(),m_option_variable.summary_string.GetCurrentValue())); - ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(false,eFormatDefault,summary_format_sp)); + DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,eFormatDefault,summary_format_sp)); if (variable_list) { @@ -447,9 +448,7 @@ protected: if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) s.PutCString (": "); } - ValueObject::DumpValueObject (result.GetOutputStream(), - valobj_sp.get(), - options); + valobj_sp->Dump(result.GetOutputStream(),options); } } } @@ -493,9 +492,7 @@ protected: Stream &output_stream = result.GetOutputStream(); options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr : NULL); - ValueObject::DumpValueObject (output_stream, - valobj_sp.get(), - options); + valobj_sp->Dump(output_stream,options); } else { @@ -571,9 +568,7 @@ protected: options.SetFormat(format); options.SetRootValueObjectName(name_cstr); - ValueObject::DumpValueObject (result.GetOutputStream(), - valobj_sp.get(), - options); + valobj_sp->Dump(result.GetOutputStream(),options); } } } diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index 7a0e204993e..d7e59fb3486 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -23,6 +23,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObjectMemory.h" +#include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -836,11 +837,9 @@ protected: if (format != eFormatDefault) valobj_sp->SetFormat (format); - ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(false,format)); + DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,format)); - ValueObject::DumpValueObject (*output_stream, - valobj_sp.get(), - options); + valobj_sp->Dump(*output_stream,options); } else { diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 7f121ecc1c3..ef431e25c3d 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -26,6 +26,7 @@ #include "lldb/Core/State.h" #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Host/Symbols.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -719,7 +720,7 @@ public: void DumpValueObject (Stream &s, VariableSP &var_sp, ValueObjectSP &valobj_sp, const char *root_name) { - ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions()); + DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions()); switch (var_sp->GetScope()) { @@ -761,10 +762,7 @@ public: options.SetRootValueObjectName(root_name); - ValueObject::DumpValueObject (s, - valobj_sp.get(), - options); - + valobj_sp->Dump(s,options); } diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 8a29934ff62..caeed72e2a7 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1981,7 +1981,7 @@ FormatPromptRecurse ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); if (return_valobj_sp) { - ValueObject::DumpValueObject (s, return_valobj_sp.get()); + return_valobj_sp->Dump(s); var_success = true; } } diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 19d17af7d99..f07b5e375d1 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -34,6 +34,7 @@ #include "lldb/Core/ValueObjectSyntheticFilter.h" #include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Host/Endian.h" @@ -3422,329 +3423,39 @@ ValueObject::ExpandArraySliceExpression(const char* expression_cstr, } } -static void -DumpValueObject_Impl (Stream &s, - ValueObject *valobj, - const ValueObject::DumpValueObjectOptions& options, - uint32_t ptr_depth, - uint32_t curr_depth) -{ - if (valobj) - { - bool update_success = valobj->UpdateValueIfNeeded (true); - - const char *root_valobj_name = - options.m_root_valobj_name.empty() ? - valobj->GetName().AsCString() : - options.m_root_valobj_name.c_str(); - - if (update_success && options.m_use_dynamic != eNoDynamicValues) - { - ValueObject *dynamic_value = valobj->GetDynamicValue(options.m_use_dynamic).get(); - if (dynamic_value) - valobj = dynamic_value; - } - - ClangASTType clang_type = valobj->GetClangType(); - const Flags type_flags (clang_type.GetTypeInfo ()); - const char *err_cstr = NULL; - const bool has_children = type_flags.Test (ClangASTType::eTypeHasChildren); - const bool has_value = type_flags.Test (ClangASTType::eTypeHasValue); - - const bool print_valobj = options.m_flat_output == false || has_value; - - if (print_valobj) - { - if (options.m_show_location) - { - s.Printf("%s: ", valobj->GetLocationAsCString()); - } - - s.Indent(); - - bool show_type = true; - // if we are at the root-level and been asked to hide the root's type, then hide it - if (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 || (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 qualified_type_name(valobj->GetQualifiedTypeName()); - if (qualified_type_name) - s.Printf("(%s) ", qualified_type_name.GetCString()); - } - - if (options.m_flat_output) - { - // If we are showing types, also qualify the C++ base classes - const bool qualify_cxx_base_classes = options.m_show_types; - if (!options.m_hide_name) - { - valobj->GetExpressionPath(s, qualify_cxx_base_classes); - s.PutCString(" ="); - } - } - else if (!options.m_hide_name) - { - const char *name_cstr = root_valobj_name ? root_valobj_name : valobj->GetName().AsCString(""); - s.Printf ("%s =", name_cstr); - } - - if (!options.m_scope_already_checked && !valobj->IsInScope()) - { - err_cstr = "out of scope"; - } - } - - std::string summary_str; - std::string value_str; - const char *val_cstr = NULL; - const char *sum_cstr = NULL; - TypeSummaryImpl* entry = options.m_summary_sp ? options.m_summary_sp.get() : valobj->GetSummaryFormat().get(); - - if (options.m_omit_summary_depth > 0) - entry = NULL; - - bool is_nil = valobj->IsObjCNil(); - - if (err_cstr == NULL) - { - if (options.m_format != eFormatDefault && options.m_format != valobj->GetFormat()) - { - valobj->GetValueAsCString(options.m_format, - value_str); - } - else - { - val_cstr = valobj->GetValueAsCString(); - if (val_cstr) - value_str = val_cstr; - } - err_cstr = valobj->GetError().AsCString(); - } - - if (err_cstr) - { - s.Printf (" <%s>\n", err_cstr); - } - else - { - const bool is_ref = type_flags.Test (ClangASTType::eTypeIsReference); - if (print_valobj) - { - if (is_nil) - sum_cstr = "nil"; - else if (options.m_omit_summary_depth == 0) - { - if (options.m_summary_sp) - { - valobj->GetSummaryAsCString(entry, summary_str); - sum_cstr = summary_str.c_str(); - } - else - sum_cstr = valobj->GetSummaryAsCString(); - } - - // 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) - if (!is_nil && !value_str.empty() && (entry == NULL || (entry->DoesPrintValue() || options.m_format != eFormatDefault) || sum_cstr == NULL) && !options.m_hide_value) - s.Printf(" %s", value_str.c_str()); - - if (sum_cstr) - s.Printf(" %s", sum_cstr); - - // let's avoid the overly verbose no description error for a nil thing - if (options.m_use_objc && !is_nil) - { - if (!options.m_hide_value || !options.m_hide_name) - s.Printf(" "); - const char *object_desc = valobj->GetObjectDescription(); - if (object_desc) - s.Printf("%s\n", object_desc); - else - s.Printf ("[no Objective-C description available]\n"); - return; - } - } - - if (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). - bool print_children = true; - - // Use a new temporary pointer depth in case we override the - // current pointer depth below... - uint32_t curr_ptr_depth = ptr_depth; - - const bool is_ptr = type_flags.Test (ClangASTType::eTypeIsPointer); - 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 (valobj->GetPointerValue (&ptr_address_type) == 0) - print_children = false; - - else if (is_ref && curr_depth == 0) - { - // 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... - curr_ptr_depth = 1; - } - - if (curr_ptr_depth == 0) - print_children = false; - } - - if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr)) - { - ValueObjectSP synth_valobj_sp = valobj->GetSyntheticValue (options.m_use_synthetic); - ValueObject* synth_valobj = (synth_valobj_sp ? synth_valobj_sp.get() : valobj); - - size_t num_children = synth_valobj->GetNumChildren(); - bool print_dotdotdot = false; - if (num_children) - { - if (options.m_flat_output) - { - if (print_valobj) - s.EOL(); - } - else - { - if (print_valobj) - s.PutCString(is_ref ? ": {\n" : " {\n"); - s.IndentMore(); - } - - const size_t max_num_children = valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); - - if (num_children > max_num_children && !options.m_ignore_cap) - { - num_children = max_num_children; - print_dotdotdot = true; - } - - ValueObject::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); - for (size_t idx=0; idx<num_children; ++idx) - { - ValueObjectSP child_sp(synth_valobj->GetChildAtIndex(idx, true)); - if (child_sp.get()) - { - DumpValueObject_Impl (s, - child_sp.get(), - child_options, - (is_ptr || is_ref) ? curr_ptr_depth - 1 : curr_ptr_depth, - curr_depth + 1); - } - } - - if (!options.m_flat_output) - { - if (print_dotdotdot) - { - ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); - Target *target = exe_ctx.GetTargetPtr(); - if (target) - target->GetDebugger().GetCommandInterpreter().ChildrenTruncated(); - s.Indent("...\n"); - } - s.IndentLess(); - s.Indent("}\n"); - } - } - else if (has_children) - { - // Aggregate, no children... - if (print_valobj) - s.PutCString(" {}\n"); - } - else - { - if (print_valobj) - s.EOL(); - } - - } - else - { - s.EOL(); - } - } - else - { - if (has_children && print_valobj) - { - s.PutCString("{...}\n"); - } - } - } - } -} - void -ValueObject::LogValueObject (Log *log, - ValueObject *valobj) +ValueObject::LogValueObject (Log *log) { - if (log && valobj) - return LogValueObject (log, valobj, DumpValueObjectOptions::DefaultOptions()); + if (log) + return LogValueObject (log, DumpValueObjectOptions::DefaultOptions()); } void -ValueObject::LogValueObject (Log *log, - ValueObject *valobj, - const DumpValueObjectOptions& options) +ValueObject::LogValueObject (Log *log, const DumpValueObjectOptions& options) { - if (log && valobj) + if (log) { StreamString s; - ValueObject::DumpValueObject (s, valobj, options); + Dump (s, options); if (s.GetSize()) log->PutCString(s.GetData()); } } void -ValueObject::DumpValueObject (Stream &s, - ValueObject *valobj) +ValueObject::Dump (Stream &s) { - if (!valobj) - return; - - DumpValueObject_Impl(s, - valobj, - DumpValueObjectOptions::DefaultOptions(), - 0, - 0); + ValueObjectPrinter printer(this,&s,DumpValueObjectOptions::DefaultOptions()); + printer.PrintValueObject(); } void -ValueObject::DumpValueObject (Stream &s, - ValueObject *valobj, - const DumpValueObjectOptions& options) +ValueObject::Dump (Stream &s, + const DumpValueObjectOptions& options) { - DumpValueObject_Impl(s, - valobj, - options, - options.m_max_ptr_depth, // max pointer depth allowed, we will go down from here - 0 // current object depth is 0 since we are just starting - ); + ValueObjectPrinter printer(this,&s,options); + printer.PrintValueObject(); } ValueObjectSP diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp new file mode 100644 index 00000000000..417b5822aab --- /dev/null +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -0,0 +1,533 @@ +//===-- 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/Interpreter/CommandInterpreter.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj, + Stream* s, + const DumpValueObjectOptions& options) : + m_orig_valobj(valobj), + m_valobj(nullptr), + m_stream(s), + options(options), + m_ptr_depth(options.m_max_ptr_depth), + m_curr_depth(0), + 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(), + m_summary(), + m_error() +{ + assert (m_orig_valobj && "cannot print a NULL ValueObject"); + assert (m_stream && "cannot print to a NULL Stream"); +} + +ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj, + Stream* s, + const DumpValueObjectOptions& options, + uint32_t ptr_depth, + uint32_t curr_depth) : + ValueObjectPrinter(valobj,s,options) +{ + m_ptr_depth = ptr_depth; + m_curr_depth = curr_depth; +} + +bool +ValueObjectPrinter::PrintValueObject () +{ + if (!GetDynamicValueIfNeeded () || m_valobj == nullptr) + return false; + + if (ShouldPrintValueObject()) + { + 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); + + m_stream->EOL(); + + return true; +} + +bool +ValueObjectPrinter::GetDynamicValueIfNeeded () +{ + bool update_success = m_orig_valobj->UpdateValueIfNeeded (true); + if (!update_success) + return false; + 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; + m_clang_type = m_valobj->GetClangType(); + 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 (ClangASTType::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 (ClangASTType::eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; + return m_is_ptr == eLazyBoolYes; +} + +bool +ValueObjectPrinter::IsRef () +{ + if (m_is_ref == eLazyBoolCalculate) + m_is_ref = m_type_flags.Test (ClangASTType::eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; + return m_is_ref == eLazyBoolYes; +} + +bool +ValueObjectPrinter::IsAggregate () +{ + if (m_is_aggregate == eLazyBoolCalculate) + m_is_aggregate = m_type_flags.Test (ClangASTType::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 qualified_type_name(m_valobj->GetQualifiedTypeName()); + if (qualified_type_name) + m_stream->Printf("(%s) ", qualified_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() || 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 +ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description, + uint32_t& curr_ptr_depth) +{ + const bool is_ref = IsRef (); + const bool is_ptr = IsPtr (); + + 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... + uint32_t curr_ptr_depth = m_ptr_depth; + + 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; + + else if (is_ref && m_curr_depth == 0) + { + // 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... + curr_ptr_depth = 1; + } + + if (curr_ptr_depth == 0) + return false; + } + + TypeSummaryImpl* entry = GetSummaryFormatter(); + + return (!entry || entry->DoesPrintChildren() || m_summary.empty()); + } + return false; +} + +ValueObject* +ValueObjectPrinter::GetValueObjectForChildrenGeneration () +{ + ValueObjectSP synth_valobj_sp = m_valobj->GetSyntheticValue (options.m_use_synthetic); + return (synth_valobj_sp ? synth_valobj_sp.get() : 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, + uint32_t 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 - 1 : 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 (uint32_t 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()) + m_stream->PutCString(" {}\n"); + } + else + { + if (ShouldPrintValueObject()) + m_stream->EOL(); + } +} + +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); + + uint32_t curr_ptr_depth = m_ptr_depth; + bool print_children = ShouldPrintChildren (is_failed_description,curr_ptr_depth); + + if (print_children) + { + PrintChildren (curr_ptr_depth); + } + else if (m_curr_depth >= options.m_max_depth && IsAggregate() && ShouldPrintValueObject()) + { + m_stream->PutCString("{...}\n"); + } +} diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 6ab4af167b6..c71ca28b033 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -1098,6 +1098,7 @@ CommandObject::g_arguments_data[] = { eArgTypeCount, "count", CommandCompletions::eNoCompletion, { NULL, false }, "An unsigned integer." }, { eArgTypeDirectoryName, "directory", CommandCompletions::eDiskDirectoryCompletion, { NULL, false }, "A directory name." }, { eArgTypeDisassemblyFlavor, "disassembly-flavor", CommandCompletions::eNoCompletion, { NULL, false }, "A disassembly flavor recognized by your disassembly plugin. Currently the only valid options are \"att\" and \"intel\" for Intel targets" }, + { eArgTypeDescriptionVerbosity, "description-verbosity", CommandCompletions::eNoCompletion, { NULL, false }, "How verbose the output of 'po' should be." }, { eArgTypeEndAddress, "end-address", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, { eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." }, { eArgTypeExpressionPath, "expr-path", CommandCompletions::eNoCompletion, { ExprPathHelpTextCallback, true }, NULL }, diff --git a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp index 0129d3ed3f8..c79f49dc1d9 100644 --- a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -15,6 +15,7 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Target/Target.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Utility/Utils.h" @@ -147,12 +148,12 @@ OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interp } } -ValueObject::DumpValueObjectOptions -OptionGroupValueObjectDisplay::GetAsDumpOptions (bool objc_is_compact, +DumpValueObjectOptions +OptionGroupValueObjectDisplay::GetAsDumpOptions (LanguageRuntimeDescriptionDisplayVerbosity lang_descr_verbosity, lldb::Format format, lldb::TypeSummaryImplSP summary_sp) { - ValueObject::DumpValueObjectOptions options; + DumpValueObjectOptions options; options.SetMaximumPointerDepth(ptr_depth); if (use_objc) options.SetShowSummary(false); @@ -169,7 +170,7 @@ OptionGroupValueObjectDisplay::GetAsDumpOptions (bool objc_is_compact, .SetFormat(format) .SetSummary(summary_sp); - if (objc_is_compact) + if (lang_descr_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact) options.SetHideRootType(use_objc) .SetHideName(use_objc) .SetHideValue(use_objc); diff --git a/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py b/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py index 9feffbe3f04..01e738adddb 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py @@ -178,7 +178,7 @@ class AdvDataFormatterTestCase(TestBase): # if the summary has an error, we still display the value self.expect("frame variable couple --summary-string \"${*var.sp.foo[0-2]\"", - substrs = ['(Couple) couple = {','sp = {','z =','"X"']) + substrs = ['(Couple) couple = {','sp = {','z =','"X"']) self.runCmd("type summary add --summary-string \"${*var.sp.x[0-2]} are low bits of integer ${*var.sp.x}. If I pretend it is an array I get ${var.sp.x[0-5]}\" Couple") diff --git a/lldb/test/lang/cpp/namespace/TestNamespace.py b/lldb/test/lang/cpp/namespace/TestNamespace.py index 52c4ad00478..a3b6366275d 100644 --- a/lldb/test/lang/cpp/namespace/TestNamespace.py +++ b/lldb/test/lang/cpp/namespace/TestNamespace.py @@ -83,12 +83,12 @@ class NamespaceTestCase(TestBase): # 'frame variable' with fully qualified name 'A::B::j' should work. self.expect("frame variable A::B::j", VARIABLES_DISPLAYED_CORRECTLY, startstr = '(int) A::B::j = 4', - patterns = [' = 4$']) + patterns = [' = 4']) # So should the anonymous namespace case. self.expect("frame variable '(anonymous namespace)::i'", VARIABLES_DISPLAYED_CORRECTLY, startstr = '(int) (anonymous namespace)::i = 3', - patterns = [' = 3$']) + patterns = [' = 3']) # rdar://problem/8660275 # test/namespace: 'expression -- i+j' not working @@ -103,9 +103,9 @@ class NamespaceTestCase(TestBase): # rdar://problem/8668674 # expression command with fully qualified namespace for a variable does not work self.expect("expression -- ::i", VARIABLES_DISPLAYED_CORRECTLY, - patterns = [' = 3$']) + patterns = [' = 3']) self.expect("expression -- A::B::j", VARIABLES_DISPLAYED_CORRECTLY, - patterns = [' = 4$']) + patterns = [' = 4']) # expression command with function in anonymous namespace self.expect("expression -- myanonfunc(3)", |