Added an error message when the user tries to add a filter when a synthetic provider for the same type is already defined in the same category

The converse is also true: an error is shown when the user tries to add a synthetic provider to a category that already has a filter for the same type

llvm-svn: 137493
This commit is contained in:
Enrico Granata 2011-08-12 19:14:27 +00:00
parent 70cb84a0f6
commit 68eb4bb421
6 changed files with 285 additions and 68 deletions

View File

@ -512,9 +512,16 @@ public:
lldb::DynamicValueType use_dynamic,
lldb::SummaryFormatSP& entry);
static bool
GetSyntheticFilter(ValueObject& vobj,
lldb::DynamicValueType use_dynamic,
lldb::SyntheticChildrenSP& entry);
GetSyntheticChildren(ValueObject& vobj,
lldb::DynamicValueType use_dynamic,
lldb::SyntheticChildrenSP& entry);
static bool
AnyMatches(ConstString type_name,
FormatCategory::FormatCategoryItems items = FormatCategory::ALL_ITEM_TYPES,
bool only_enabled = true,
const char** matching_category = NULL,
FormatCategory::FormatCategoryItems* matching_type = NULL);
class NamedSummaryFormats
{

View File

@ -608,8 +608,10 @@ class CategoryMap;
class FormatCategory
{
private:
typedef FormatNavigator<const char*, SummaryFormat> SummaryNavigator;
typedef FormatNavigator<lldb::RegularExpressionSP, SummaryFormat> RegexSummaryNavigator;
typedef FormatNavigator<const char*, SyntheticFilter> FilterNavigator;
typedef FormatNavigator<lldb::RegularExpressionSP, SyntheticFilter> RegexFilterNavigator;
@ -655,6 +657,15 @@ private:
friend class CategoryMap;
friend class FormatNavigator<const char*, SummaryFormat>;
friend class FormatNavigator<lldb::RegularExpressionSP, SummaryFormat>;
friend class FormatNavigator<const char*, SyntheticFilter>;
friend class FormatNavigator<lldb::RegularExpressionSP, SyntheticFilter>;
friend class FormatNavigator<const char*, SyntheticScriptProvider>;
friend class FormatNavigator<lldb::RegularExpressionSP, SyntheticScriptProvider>;
public:
enum FormatCategoryItem
@ -824,17 +835,17 @@ public:
void
Clear(FormatCategoryItems items = ALL_ITEM_TYPES)
{
if ( (items & eSummary) )
if ( (items & eSummary) == eSummary )
m_summary_nav->Clear();
if ( (items & eRegexSummary) )
if ( (items & eRegexSummary) == eRegexSummary )
m_regex_summary_nav->Clear();
if ( (items & eFilter) )
if ( (items & eFilter) == eFilter )
m_filter_nav->Clear();
if ( (items & eRegexFilter) )
if ( (items & eRegexFilter) == eRegexFilter )
m_regex_filter_nav->Clear();
if ( (items & eSynth) )
if ( (items & eSynth) == eSynth )
m_synth_nav->Clear();
if ( (items & eRegexSynth) )
if ( (items & eRegexSynth) == eRegexSynth )
m_regex_synth_nav->Clear();
}
@ -843,17 +854,17 @@ public:
FormatCategoryItems items = ALL_ITEM_TYPES)
{
bool success = false;
if ( (items & eSummary) )
if ( (items & eSummary) == eSummary )
success = m_summary_nav->Delete(name) || success;
if ( (items & eRegexSummary) )
if ( (items & eRegexSummary) == eRegexSummary )
success = m_regex_summary_nav->Delete(name) || success;
if ( (items & eFilter) )
if ( (items & eFilter) == eFilter )
success = m_filter_nav->Delete(name) || success;
if ( (items & eRegexFilter) )
if ( (items & eRegexFilter) == eRegexFilter )
success = m_regex_filter_nav->Delete(name) || success;
if ( (items & eSynth) )
if ( (items & eSynth) == eSynth )
success = m_synth_nav->Delete(name) || success;
if ( (items & eRegexSynth) )
if ( (items & eRegexSynth) == eRegexSynth )
success = m_regex_synth_nav->Delete(name) || success;
return success;
}
@ -862,17 +873,17 @@ public:
GetCount(FormatCategoryItems items = ALL_ITEM_TYPES)
{
uint32_t count = 0;
if ( (items & eSummary) )
if ( (items & eSummary) == eSummary )
count += m_summary_nav->GetCount();
if ( (items & eRegexSummary) )
if ( (items & eRegexSummary) == eRegexSummary )
count += m_regex_summary_nav->GetCount();
if ( (items & eFilter) )
if ( (items & eFilter) == eFilter )
count += m_filter_nav->GetCount();
if ( (items & eRegexFilter) )
if ( (items & eRegexFilter) == eRegexFilter )
count += m_regex_filter_nav->GetCount();
if ( (items & eSynth) )
if ( (items & eSynth) == eSynth )
count += m_synth_nav->GetCount();
if ( (items & eRegexSynth) )
if ( (items & eRegexSynth) == eRegexSynth )
count += m_regex_synth_nav->GetCount();
return count;
}
@ -883,6 +894,89 @@ public:
return m_name;
}
bool
AnyMatches(ConstString type_name,
FormatCategoryItems items = ALL_ITEM_TYPES,
bool only_enabled = true,
const char** matching_category = NULL,
FormatCategoryItems* matching_type = NULL)
{
if (!IsEnabled() && only_enabled)
return false;
SummaryFormat::SharedPointer summary;
SyntheticFilter::SharedPointer filter;
SyntheticScriptProvider::SharedPointer synth;
if ( (items & eSummary) == eSummary )
{
if (m_summary_nav->Get(type_name.AsCString(), summary))
{
if (matching_category)
*matching_category = m_name.c_str();
if (matching_type)
*matching_type = eSummary;
return true;
}
}
if ( (items & eRegexSummary) == eRegexSummary )
{
if (m_regex_summary_nav->Get(type_name.AsCString(), summary))
{
if (matching_category)
*matching_category = m_name.c_str();
if (matching_type)
*matching_type = eRegexSummary;
return true;
}
}
if ( (items & eFilter) == eFilter )
{
if (m_filter_nav->Get(type_name.AsCString(), filter))
{
if (matching_category)
*matching_category = m_name.c_str();
if (matching_type)
*matching_type = eFilter;
return true;
}
}
if ( (items & eRegexFilter) == eRegexFilter )
{
if (m_regex_filter_nav->Get(type_name.AsCString(), filter))
{
if (matching_category)
*matching_category = m_name.c_str();
if (matching_type)
*matching_type = eRegexFilter;
return true;
}
}
if ( (items & eSynth) == eSynth )
{
if (m_synth_nav->Get(type_name.AsCString(), synth))
{
if (matching_category)
*matching_category = m_name.c_str();
if (matching_type)
*matching_type = eSynth;
return true;
}
}
if ( (items & eRegexSynth) == eRegexSynth )
{
if (m_regex_synth_nav->Get(type_name.AsCString(), synth))
{
if (matching_category)
*matching_category = m_name.c_str();
if (matching_type)
*matching_type = eRegexSynth;
return true;
}
}
return false;
}
typedef lldb::SharedPtr<FormatCategory>::Type SharedPointer;
};
@ -1052,6 +1146,28 @@ public:
}
}
bool
AnyMatches(ConstString type_name,
FormatCategory::FormatCategoryItems items = FormatCategory::ALL_ITEM_TYPES,
bool only_enabled = true,
const char** matching_category = NULL,
FormatCategory::FormatCategoryItems* matching_type = NULL)
{
Mutex::Locker(m_map_mutex);
MapIterator pos, end = m_map.end();
for (pos = m_map.begin(); pos != end; pos++)
{
if (pos->second->AnyMatches(type_name,
items,
only_enabled,
matching_category,
matching_type))
return true;
}
return false;
}
uint32_t
GetCount()
{
@ -1265,6 +1381,20 @@ public:
{
return m_categories_map.Get(vobj, entry, use_dynamic);
}
bool
AnyMatches(ConstString type_name,
FormatCategory::FormatCategoryItems items = FormatCategory::ALL_ITEM_TYPES,
bool only_enabled = true,
const char** matching_category = NULL,
FormatCategory::FormatCategoryItems* matching_type = NULL)
{
return m_categories_map.AnyMatches(type_name,
items,
only_enabled,
matching_category,
matching_type);
}
static bool
GetFormatFromCString (const char *format_cstr,

View File

@ -3018,15 +3018,24 @@ public:
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(options->m_category.c_str()), category);
Error error;
for (size_t i = 0; i < options->m_target_types.GetSize(); i++) {
const char *type_name = options->m_target_types.GetStringAtIndex(i);
ConstString typeCS(type_name);
if (typeCS)
CommandObjectTypeSynthAdd::AddSynth(typeCS,
synth_provider,
options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth,
options->m_category,
NULL);
{
if (!CommandObjectTypeSynthAdd::AddSynth(typeCS,
synth_provider,
options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth,
options->m_category,
&error))
{
out_stream->Printf("%s\n", error.AsCString());
out_stream->Flush();
return;
}
}
else
{
out_stream->Printf ("Internal error #6: no script attached.\n");
@ -3126,15 +3135,24 @@ CommandObjectTypeSynthAdd::Execute_PythonClass (Args& command, CommandReturnObje
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category.c_str()), category);
Error error;
for (size_t i = 0; i < argc; i++) {
const char* typeA = command.GetArgumentAtIndex(i);
ConstString typeCS(typeA);
if (typeCS)
AddSynth(typeCS,
entry,
m_options.m_regex ? eRegexSynth : eRegularSynth,
m_options.m_category,
NULL);
{
if (!AddSynth(typeCS,
entry,
m_options.m_regex ? eRegexSynth : eRegularSynth,
m_options.m_category,
&error))
{
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
return false;
}
}
else
{
result.AppendError("empty typenames not allowed");
@ -3175,6 +3193,15 @@ CommandObjectTypeSynthAdd::AddSynth(const ConstString& type_name,
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(category_name.c_str()), category);
if (category->AnyMatches(type_name,
FormatCategory::eFilter | FormatCategory::eRegexFilter,
false))
{
if (error)
error->SetErrorStringWithFormat("cannot add synthetic for type %s when filter is defined in same category!", type_name.AsCString());
return false;
}
if (type == eRegexSynth)
{
RegularExpressionSP typeRX(new RegularExpression());
@ -3327,23 +3354,32 @@ private:
return &m_options;
}
enum SynthFormatType
enum FilterFormatType
{
eRegularSynth,
eRegexSynth,
eRegularFilter,
eRegexFilter,
};
bool
AddSynth(const ConstString& type_name,
SyntheticChildrenSP entry,
SynthFormatType type,
std::string category_name,
Error* error)
AddFilter(const ConstString& type_name,
SyntheticChildrenSP entry,
FilterFormatType type,
std::string category_name,
Error* error)
{
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(category_name.c_str()), category);
if (type == eRegexSynth)
if (category->AnyMatches(type_name,
FormatCategory::eSynth | FormatCategory::eRegexSynth,
false))
{
if (error)
error->SetErrorStringWithFormat("cannot add filter for type %s when synthetic is defined in same category!", type_name.AsCString());
return false;
}
if (type == eRegexFilter)
{
RegularExpressionSP typeRX(new RegularExpression());
if (!typeRX->Compile(type_name.GetCString()))
@ -3430,15 +3466,24 @@ public:
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category.c_str()), category);
Error error;
for (size_t i = 0; i < argc; i++) {
const char* typeA = command.GetArgumentAtIndex(i);
ConstString typeCS(typeA);
if (typeCS)
AddSynth(typeCS,
entry,
m_options.m_regex ? eRegexSynth : eRegularSynth,
m_options.m_category,
NULL);
{
if (!AddFilter(typeCS,
entry,
m_options.m_regex ? eRegexFilter : eRegularFilter,
m_options.m_category,
&error))
{
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
return false;
}
}
else
{
result.AppendError("empty typenames not allowed");

View File

@ -1837,13 +1837,27 @@ Debugger::Formatting::GetSummaryFormat(ValueObject& vobj,
return GetFormatManager().Get(vobj, entry, use_dynamic);
}
bool
Debugger::Formatting::GetSyntheticFilter(ValueObject& vobj,
lldb::DynamicValueType use_dynamic,
lldb::SyntheticChildrenSP& entry)
Debugger::Formatting::GetSyntheticChildren(ValueObject& vobj,
lldb::DynamicValueType use_dynamic,
lldb::SyntheticChildrenSP& entry)
{
return GetFormatManager().Get(vobj, entry, use_dynamic);
}
bool
Debugger::Formatting::AnyMatches(ConstString type_name,
FormatCategory::FormatCategoryItems items,
bool only_enabled,
const char** matching_category,
FormatCategory::FormatCategoryItems* matching_type)
{
return GetFormatManager().AnyMatches(type_name,
items,
only_enabled,
matching_category,
matching_type);
}
bool
Debugger::Formatting::Categories::Get(const ConstString &category, lldb::FormatCategorySP &entry)
{

View File

@ -243,7 +243,7 @@ ValueObject::UpdateFormatsIfNeeded(lldb::DynamicValueType use_dynamic)
Debugger::Formatting::ValueFormats::Get(*this, lldb::eNoDynamicValues, m_last_value_format);
Debugger::Formatting::GetSummaryFormat(*this, use_dynamic, m_last_summary_format);
Debugger::Formatting::GetSyntheticFilter(*this, use_dynamic, m_last_synthetic_filter);
Debugger::Formatting::GetSyntheticChildren(*this, use_dynamic, m_last_synthetic_filter);
m_last_format_mgr_revision = Debugger::Formatting::ValueFormats::GetCurrentRevision();
m_last_format_mgr_dynamic = use_dynamic;

View File

@ -136,18 +136,48 @@ class DataFormatterTestCase(TestBase):
'fake_a = 218103808',
'a = 12'])
# now mix synth and filter and check consistent output
self.runCmd("type filter add foo --child b --child j")
self.expect('frame variable f00_1',
# now add a filter.. it should fail
self.expect("type filter add foo --child b --child j", error=True,
substrs = ['cannot add'])
# we get the synth again..
self.expect('frame variable f00_1', matching=False,
substrs = ['b = 1',
'j = 17'])
self.expect("frame variable -P 1 f00_ptr",
substrs = ['r = 45',
'fake_a = 218103808',
'a = 12'])
# now delete the synth and add the filter
self.runCmd("type synth delete foo")
self.runCmd("type filter add foo --child b --child j")
self.expect('frame variable f00_1',
substrs = ['b = 1',
'j = 17'])
self.expect("frame variable -P 1 f00_ptr", matching=False,
substrs = ['r = 45',
'fake_a = 218103808',
'a = 12'])
# now add the synth again to see that it prevails
# now add the synth and it should fail
self.expect("type synth add -l fooSynthProvider foo", error=True,
substrs = ['cannot add'])
# check the listing
self.expect('type synth list', matching=False,
substrs = ['foo',
'Python class fooSynthProvider'])
self.expect('type filter list',
substrs = ['foo',
'.b',
'.j'])
# delete the filter, add the synth
self.runCmd("type filter delete foo")
self.runCmd("type synth add -l fooSynthProvider foo")
self.expect('frame variable f00_1', matching=False,
substrs = ['b = 1',
'j = 17'])
@ -160,7 +190,7 @@ class DataFormatterTestCase(TestBase):
self.expect('type synth list',
substrs = ['foo',
'Python class fooSynthProvider'])
self.expect('type filter list',
self.expect('type filter list', matching=False,
substrs = ['foo',
'.b',
'.j'])
@ -168,19 +198,6 @@ class DataFormatterTestCase(TestBase):
# delete the synth and check that we get good output
self.runCmd("type synth delete foo")
# first let the filter win
self.expect('frame variable f00_1',
substrs = ['b = 1',
'j = 17'])
self.expect("frame variable -P 1 f00_ptr", matching=False,
substrs = ['r = 45',
'fake_a = 218103808',
'a = 12'])
# then delete the filter
self.runCmd("type filter delete foo")
# and show real children
self.expect("frame variable f00_1",
substrs = ['a = 280',
'b = 1',
@ -451,7 +468,11 @@ class DataFormatterTestCase(TestBase):
self.runCmd("frame variable ii -T")
self.runCmd("script from StdMapSynthProvider import *")
self.runCmd("type summary add -x \"std::map<\" -f \"map has ${svar%#} items\" -e")
self.runCmd("type summary add -x \"std::map<\" -f \"map has ${svar%#} items\" -e")
#import time
#time.sleep(30)
self.runCmd("type synth add -x \"std::map<\" -l StdMapSynthProvider")