Add option eTypeOptionHideEmptyAggregates.
Summary: For certain data structures, when the synthetic child provider returns zero children, a summary like "Empty instance of <typename>" could be more appropriate than something like "size=0 {}". This new option helps hide the trailing "{}". This is also exposed with a -h option for the command "type summary add". Reviewers: granata.enrico Subscribers: lldb-commits Differential Revision: http://reviews.llvm.org/D11473 llvm-svn: 243166
This commit is contained in:
parent
fd4dfdcea1
commit
d26eb907bc
|
@ -162,6 +162,22 @@ namespace lldb_private {
|
||||||
m_flags &= ~lldb::eTypeOptionHideChildren;
|
m_flags &= ~lldb::eTypeOptionHideChildren;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GetHideEmptyAggregates () const
|
||||||
|
{
|
||||||
|
return (m_flags & lldb::eTypeOptionHideEmptyAggregates) == lldb::eTypeOptionHideEmptyAggregates;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flags&
|
||||||
|
SetHideEmptyAggregates (bool value = true)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
m_flags |= lldb::eTypeOptionHideEmptyAggregates;
|
||||||
|
else
|
||||||
|
m_flags &= ~lldb::eTypeOptionHideEmptyAggregates;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GetDontShowValue () const
|
GetDontShowValue () const
|
||||||
|
@ -279,6 +295,12 @@ namespace lldb_private {
|
||||||
{
|
{
|
||||||
return !m_flags.GetDontShowChildren();
|
return !m_flags.GetDontShowChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
DoesPrintEmptyAggregates () const
|
||||||
|
{
|
||||||
|
return !m_flags.GetHideEmptyAggregates();
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
DoesPrintValue (ValueObject* valobj) const
|
DoesPrintValue (ValueObject* valobj) const
|
||||||
|
|
|
@ -344,6 +344,9 @@ protected:
|
||||||
bool
|
bool
|
||||||
ShouldPrintChildren (bool is_failed_description,
|
ShouldPrintChildren (bool is_failed_description,
|
||||||
uint32_t& curr_ptr_depth);
|
uint32_t& curr_ptr_depth);
|
||||||
|
|
||||||
|
bool
|
||||||
|
ShouldExpandEmptyAggregates ();
|
||||||
|
|
||||||
ValueObject*
|
ValueObject*
|
||||||
GetValueObjectForChildrenGeneration ();
|
GetValueObjectForChildrenGeneration ();
|
||||||
|
|
|
@ -729,15 +729,16 @@ namespace lldb {
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
FLAGS_ENUM(TypeOptions)
|
FLAGS_ENUM(TypeOptions)
|
||||||
{
|
{
|
||||||
eTypeOptionNone = (0u),
|
eTypeOptionNone = (0u),
|
||||||
eTypeOptionCascade = (1u << 0),
|
eTypeOptionCascade = (1u << 0),
|
||||||
eTypeOptionSkipPointers = (1u << 1),
|
eTypeOptionSkipPointers = (1u << 1),
|
||||||
eTypeOptionSkipReferences = (1u << 2),
|
eTypeOptionSkipReferences = (1u << 2),
|
||||||
eTypeOptionHideChildren = (1u << 3),
|
eTypeOptionHideChildren = (1u << 3),
|
||||||
eTypeOptionHideValue = (1u << 4),
|
eTypeOptionHideValue = (1u << 4),
|
||||||
eTypeOptionShowOneLiner = (1u << 5),
|
eTypeOptionShowOneLiner = (1u << 5),
|
||||||
eTypeOptionHideNames = (1u << 6),
|
eTypeOptionHideNames = (1u << 6),
|
||||||
eTypeOptionNonCacheable = (1u << 7)
|
eTypeOptionNonCacheable = (1u << 7),
|
||||||
|
eTypeOptionHideEmptyAggregates = (1u << 8)
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
|
@ -1438,6 +1438,9 @@ CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue (uint32_t option_idx
|
||||||
case 'e':
|
case 'e':
|
||||||
m_flags.SetDontShowChildren(false);
|
m_flags.SetDontShowChildren(false);
|
||||||
break;
|
break;
|
||||||
|
case 'h':
|
||||||
|
m_flags.SetHideEmptyAggregates(true);
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
m_flags.SetDontShowValue(true);
|
m_flags.SetDontShowValue(true);
|
||||||
break;
|
break;
|
||||||
|
@ -1924,6 +1927,7 @@ CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
|
||||||
{ LLDB_OPT_SET_3, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type."},
|
{ LLDB_OPT_SET_3, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type."},
|
||||||
{ LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Input Python code to use for this type manually."},
|
{ LLDB_OPT_SET_3, false, "input-python", 'P', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Input Python code to use for this type manually."},
|
||||||
{ LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines."},
|
{ LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines."},
|
||||||
|
{ LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "hide-empty", 'h', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Do not expand aggregate data types with no children."},
|
||||||
{ LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "A name for this summary string."},
|
{ LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName, "A name for this summary string."},
|
||||||
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
|
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
|
||||||
};
|
};
|
||||||
|
|
|
@ -480,6 +480,17 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ValueObjectPrinter::ShouldExpandEmptyAggregates ()
|
||||||
|
{
|
||||||
|
TypeSummaryImpl* entry = GetSummaryFormatter();
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return entry->DoesPrintEmptyAggregates();
|
||||||
|
}
|
||||||
|
|
||||||
ValueObject*
|
ValueObject*
|
||||||
ValueObjectPrinter::GetValueObjectForChildrenGeneration ()
|
ValueObjectPrinter::GetValueObjectForChildrenGeneration ()
|
||||||
{
|
{
|
||||||
|
@ -582,7 +593,7 @@ ValueObjectPrinter::PrintChildren (uint32_t curr_ptr_depth)
|
||||||
if (ShouldPrintValueObject())
|
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 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())
|
if (m_valobj->DoesProvideSyntheticValue() || !ShouldExpandEmptyAggregates())
|
||||||
m_stream->PutCString( "\n");
|
m_stream->PutCString( "\n");
|
||||||
else
|
else
|
||||||
m_stream->PutCString(" {}\n");
|
m_stream->PutCString(" {}\n");
|
||||||
|
|
|
@ -208,6 +208,12 @@ class SynthDataFormatterTestCase(TestBase):
|
||||||
self.expect('frame variable bag_bag',
|
self.expect('frame variable bag_bag',
|
||||||
substrs = ['x.z = 12'])
|
substrs = ['x.z = 12'])
|
||||||
|
|
||||||
|
self.runCmd('type summary add -e -s "I am always empty but have" EmptyStruct')
|
||||||
|
self.expect('frame variable es', substrs = ["I am always empty but have {}"])
|
||||||
|
self.runCmd('type summary add -e -h -s "I am really empty" EmptyStruct')
|
||||||
|
self.expect('frame variable es', substrs = ["I am really empty"])
|
||||||
|
self.expect('frame variable es', substrs = ["I am really empty {}"], matching=False)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import atexit
|
import atexit
|
||||||
|
|
|
@ -46,6 +46,8 @@ struct BagOfBags
|
||||||
q(20.11) {}
|
q(20.11) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EmptyStruct {};
|
||||||
|
|
||||||
struct Plenty
|
struct Plenty
|
||||||
{
|
{
|
||||||
BagOfInts *some_values;
|
BagOfInts *some_values;
|
||||||
|
@ -70,6 +72,7 @@ int main (int argc, const char * argv[])
|
||||||
BagOfFloats float_bag(2.71);
|
BagOfFloats float_bag(2.71);
|
||||||
|
|
||||||
BagOfBags bag_bag;
|
BagOfBags bag_bag;
|
||||||
|
EmptyStruct es;
|
||||||
|
|
||||||
Plenty plenty_of_stuff(5,true,false);
|
Plenty plenty_of_stuff(5,true,false);
|
||||||
|
|
||||||
|
|
|
@ -302,6 +302,10 @@ class SBFormattersAPITestCase(TestBase):
|
||||||
self.assertTrue(summary.IsValid(), "no summary found for foo* when one was in place")
|
self.assertTrue(summary.IsValid(), "no summary found for foo* when one was in place")
|
||||||
self.assertTrue(summary.GetData() == "hello static world", "wrong summary found for foo*")
|
self.assertTrue(summary.GetData() == "hello static world", "wrong summary found for foo*")
|
||||||
|
|
||||||
|
self.expect("frame variable e1", substrs=["I am an empty Empty1 {}"])
|
||||||
|
self.expect("frame variable e2", substrs=["I am an empty Empty2"])
|
||||||
|
self.expect("frame variable e2", substrs=["I am an empty Empty2 {}"], matching=False)
|
||||||
|
|
||||||
def force_synth_off(self):
|
def force_synth_off(self):
|
||||||
"""Test that one can have the public API return non-synthetic SBValues if desired"""
|
"""Test that one can have the public API return non-synthetic SBValues if desired"""
|
||||||
self.runCmd("file no_synth", CURRENT_EXECUTABLE_SET)
|
self.runCmd("file no_synth", CURRENT_EXECUTABLE_SET)
|
||||||
|
|
|
@ -26,6 +26,9 @@ struct CCC
|
||||||
int a, b, c;
|
int a, b, c;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Empty1 { void *data; };
|
||||||
|
struct Empty2 { void *data; };
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char const *argv[]) {
|
int main(int argc, char const *argv[]) {
|
||||||
JustAStruct foo;
|
JustAStruct foo;
|
||||||
|
@ -49,5 +52,8 @@ int main(int argc, char const *argv[]) {
|
||||||
|
|
||||||
CCC ccc = {111, 222, 333};
|
CCC ccc = {111, 222, 333};
|
||||||
|
|
||||||
|
Empty1 e1;
|
||||||
|
Empty2 e2;
|
||||||
|
|
||||||
return 0; // Set break point at this line.
|
return 0; // Set break point at this line.
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,36 @@ class CCCSynthProvider(object):
|
||||||
return self._sbvalue.GetChildMemberWithName("c")
|
return self._sbvalue.GetChildMemberWithName("c")
|
||||||
|
|
||||||
|
|
||||||
|
def empty1_summary(sbvalue, internal_dict):
|
||||||
|
return "I am an empty Empty1"
|
||||||
|
|
||||||
|
|
||||||
|
class Empty1SynthProvider(object):
|
||||||
|
def __init__(self, sbvalue, internal_dict):
|
||||||
|
self._sbvalue = sbvalue
|
||||||
|
|
||||||
|
def num_children(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_child_at_index(self, index):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def empty2_summary(sbvalue, internal_dict):
|
||||||
|
return "I am an empty Empty2"
|
||||||
|
|
||||||
|
|
||||||
|
class Empty2SynthProvider(object):
|
||||||
|
def __init__(self, sbvalue, internal_dict):
|
||||||
|
self._sbvalue = sbvalue
|
||||||
|
|
||||||
|
def num_children(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_child_at_index(self, index):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def __lldb_init_module(debugger,dict):
|
def __lldb_init_module(debugger,dict):
|
||||||
debugger.CreateCategory("JASSynth").AddTypeSynthetic(lldb.SBTypeNameSpecifier("JustAStruct"),
|
debugger.CreateCategory("JASSynth").AddTypeSynthetic(lldb.SBTypeNameSpecifier("JustAStruct"),
|
||||||
lldb.SBTypeSynthetic.CreateWithClassName("synth.jasSynthProvider"))
|
lldb.SBTypeSynthetic.CreateWithClassName("synth.jasSynthProvider"))
|
||||||
|
@ -60,5 +90,16 @@ def __lldb_init_module(debugger,dict):
|
||||||
lldb.SBTypeNameSpecifier("CCC"),
|
lldb.SBTypeNameSpecifier("CCC"),
|
||||||
lldb.SBTypeSummary.CreateWithFunctionName("synth.ccc_summary",
|
lldb.SBTypeSummary.CreateWithFunctionName("synth.ccc_summary",
|
||||||
lldb.eTypeOptionCascade))
|
lldb.eTypeOptionCascade))
|
||||||
|
cat.AddTypeSynthetic(
|
||||||
|
lldb.SBTypeNameSpecifier("Empty1"),
|
||||||
|
lldb.SBTypeSynthetic.CreateWithClassName("synth.Empty1SynthProvider"))
|
||||||
|
cat.AddTypeSummary(
|
||||||
|
lldb.SBTypeNameSpecifier("Empty1"),
|
||||||
|
lldb.SBTypeSummary.CreateWithFunctionName("synth.empty1_summary"))
|
||||||
|
cat.AddTypeSynthetic(
|
||||||
|
lldb.SBTypeNameSpecifier("Empty2"),
|
||||||
|
lldb.SBTypeSynthetic.CreateWithClassName("synth.Empty2SynthProvider"))
|
||||||
|
cat.AddTypeSummary(
|
||||||
|
lldb.SBTypeNameSpecifier("Empty2"),
|
||||||
|
lldb.SBTypeSummary.CreateWithFunctionName("synth.empty2_summary",
|
||||||
|
lldb.eTypeOptionHideEmptyAggregates))
|
||||||
|
|
Loading…
Reference in New Issue