diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 17d48d3b1082..8b4f24df67c0 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -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 { diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h index 4991e6b7869e..2d4644e68a02 100644 --- a/lldb/include/lldb/Core/FormatManager.h +++ b/lldb/include/lldb/Core/FormatManager.h @@ -608,8 +608,10 @@ class CategoryMap; class FormatCategory { private: + typedef FormatNavigator SummaryNavigator; typedef FormatNavigator RegexSummaryNavigator; + typedef FormatNavigator FilterNavigator; typedef FormatNavigator RegexFilterNavigator; @@ -655,6 +657,15 @@ private: friend class CategoryMap; + friend class FormatNavigator; + friend class FormatNavigator; + + friend class FormatNavigator; + friend class FormatNavigator; + + friend class FormatNavigator; + friend class FormatNavigator; + 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::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, diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index 4fa34eb625bc..ff51bd12d9be 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -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"); diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 0c62a4f80474..f4b640d56099 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -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) { diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 07adaed7d825..26b7a48cc4c2 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -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; diff --git a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py index 3403e7b16ce2..a390d773db1b 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py @@ -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")