Index: lldb/include/lldb/Core/ValueObject.h =================================================================== --- lldb/include/lldb/Core/ValueObject.h +++ lldb/include/lldb/Core/ValueObject.h @@ -456,6 +456,12 @@ // The functions below should NOT be modified by subclasses const Status &GetError(); + // Store error from Expected<> parameter unless some error is already stored. + template void TakeError(llvm::Expected &&e) { + if (!e && !GetError().Fail()) + m_error = Status(e.takeError()); + } + ConstString GetName() const; virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create); Index: lldb/include/lldb/DataFormatters/FormatClasses.h =================================================================== --- lldb/include/lldb/DataFormatters/FormatClasses.h +++ lldb/include/lldb/DataFormatters/FormatClasses.h @@ -160,6 +160,24 @@ DISALLOW_COPY_AND_ASSIGN(TypeNameSpecifierImpl); }; +class FormatDupError : public llvm::ErrorInfo { +public: + static char ID; + + FormatDupError(lldb::RegularExpressionSP regex1, + lldb::RegularExpressionSP regex2, ConstString str); + + void log(llvm::raw_ostream &OS) const override; + + std::error_code convertToErrorCode() const override; + +private: + lldb::RegularExpressionSP m_regex1, m_regex2; + ConstString m_str; +}; + +bool FormatDropExpected(llvm::Expected &&e); + } // namespace lldb_private #endif // lldb_FormatClasses_h_ Index: lldb/include/lldb/DataFormatters/FormattersContainer.h =================================================================== --- lldb/include/lldb/DataFormatters/FormattersContainer.h +++ lldb/include/lldb/DataFormatters/FormattersContainer.h @@ -204,11 +204,13 @@ return ret; } - bool Get(ConstString type, MapValueType &entry) { + // See FormatDropExpected how to handle the return value. + llvm::Expected Get(ConstString type, MapValueType &entry) { return Get_Impl(type, entry, static_cast(nullptr)); } - bool GetExact(ConstString type, MapValueType &entry) { + // See FormatDropExpected how to handle the return value. + llvm::Expected GetExact(ConstString type, MapValueType &entry) { return GetExact_Impl(type, entry, static_cast(nullptr)); } @@ -262,12 +264,15 @@ return false; } - bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) { + // See FormatDropExpected how to handle the return value. + llvm::Expected Get_Impl(ConstString type, MapValueType &entry, + ConstString *dummy) { return m_format_map.Get(type, entry); } - bool GetExact_Impl(ConstString type, MapValueType &entry, - ConstString *dummy) { + // See FormatDropExpected how to handle the return value. + llvm::Expected GetExact_Impl(ConstString type, MapValueType &entry, + ConstString *dummy) { return Get_Impl(type, entry, static_cast(nullptr)); } @@ -291,19 +296,25 @@ new TypeNameSpecifierImpl(regex->GetText().str().c_str(), true)); } - bool Get_Impl(ConstString key, MapValueType &value, - lldb::RegularExpressionSP *dummy) { + // See FormatDropExpected how to handle the return value. + llvm::Expected Get_Impl(ConstString key, MapValueType &value, + lldb::RegularExpressionSP *dummy) { llvm::StringRef key_str = key.GetStringRef(); std::lock_guard guard(m_format_map.mutex()); MapIterator pos, end = m_format_map.map().end(); + MapIterator found = end; for (pos = m_format_map.map().begin(); pos != end; pos++) { lldb::RegularExpressionSP regex = pos->first; if (regex->Execute(key_str)) { - value = pos->second; - return true; + if (found != end) + return llvm::make_error(found->first, regex, key); + found = pos; } } - return false; + if (found == end) + return false; + value = found->second; + return true; } bool GetExact_Impl(ConstString key, MapValueType &value, @@ -320,21 +331,28 @@ return false; } - bool Get(const FormattersMatchVector &candidates, MapValueType &entry, - uint32_t *reason) { + // See FormatDropExpected how to handle the return value. + llvm::Expected Get(const FormattersMatchVector &candidates, + MapValueType &entry, uint32_t *reason) { + llvm::Expected retval(false); for (const FormattersMatchCandidate &candidate : candidates) { - if (Get(candidate.GetTypeName(), entry)) { + llvm::Expected got = Get(candidate.GetTypeName(), entry); + if (!got) { + FormatDropExpected(std::move(retval)); + retval = std::move(got); + } else if (*got) { if (candidate.IsMatch(entry) == false) { entry.reset(); continue; } else { if (reason) *reason = candidate.GetReason(); + FormatDropExpected(std::move(retval)); return true; } } } - return false; + return retval; } }; Index: lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py +++ lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py @@ -8,6 +8,7 @@ import lldb from lldbsuite.test.lldbtest import * import lldbsuite.test.lldbutil as lldbutil +import re class AdvDataFormatterTestCase(TestBase): @@ -130,9 +131,21 @@ self.expect("frame variable int_array", substrs=['1,2']) + # FixArrayTypeNameWithRegex converts "int []" into "int \[[0-9]+\]" + # which becomes ambiguous for some string against "int \[[0-9]\]". self.runCmd( 'type summary add --summary-string \"${var[0-1]}\" "int []"') + self.expect("frame variable int_array", + patterns=['''int_array = ''' + .format(re.escape('''int \\[[0-9]\\]'''), + re.escape('''int \\[[0-9]+\\]'''), + re.escape('''int [5]'''))]) + + self.runCmd("type summary clear") + self.runCmd( + 'type summary add --summary-string \"${var[0-1]}\" "int []"') self.expect("frame variable int_array", substrs=['1,2']) Index: lldb/source/API/SBTypeCategory.cpp =================================================================== --- lldb/source/API/SBTypeCategory.cpp +++ lldb/source/API/SBTypeCategory.cpp @@ -199,11 +199,11 @@ lldb::TypeFilterImplSP children_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexTypeFiltersContainer()->GetExact( - ConstString(spec.GetName()), children_sp); + FormatDropExpected(m_opaque_sp->GetRegexTypeFiltersContainer()->GetExact( + ConstString(spec.GetName()), children_sp)); else - m_opaque_sp->GetTypeFiltersContainer()->GetExact( - ConstString(spec.GetName()), children_sp); + FormatDropExpected(m_opaque_sp->GetTypeFiltersContainer()->GetExact( + ConstString(spec.GetName()), children_sp)); if (!children_sp) return LLDB_RECORD_RESULT(lldb::SBTypeFilter()); @@ -226,11 +226,11 @@ lldb::TypeFormatImplSP format_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexTypeFormatsContainer()->GetExact( - ConstString(spec.GetName()), format_sp); + FormatDropExpected(m_opaque_sp->GetRegexTypeFormatsContainer()->GetExact( + ConstString(spec.GetName()), format_sp)); else - m_opaque_sp->GetTypeFormatsContainer()->GetExact( - ConstString(spec.GetName()), format_sp); + FormatDropExpected(m_opaque_sp->GetTypeFormatsContainer()->GetExact( + ConstString(spec.GetName()), format_sp)); if (!format_sp) return LLDB_RECORD_RESULT(lldb::SBTypeFormat()); @@ -251,11 +251,11 @@ lldb::TypeSummaryImplSP summary_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexTypeSummariesContainer()->GetExact( - ConstString(spec.GetName()), summary_sp); + FormatDropExpected(m_opaque_sp->GetRegexTypeSummariesContainer()->GetExact( + ConstString(spec.GetName()), summary_sp)); else - m_opaque_sp->GetTypeSummariesContainer()->GetExact( - ConstString(spec.GetName()), summary_sp); + FormatDropExpected(m_opaque_sp->GetTypeSummariesContainer()->GetExact( + ConstString(spec.GetName()), summary_sp)); if (!summary_sp) return LLDB_RECORD_RESULT(lldb::SBTypeSummary()); @@ -276,11 +276,11 @@ lldb::SyntheticChildrenSP children_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexTypeSyntheticsContainer()->GetExact( - ConstString(spec.GetName()), children_sp); + FormatDropExpected(m_opaque_sp->GetRegexTypeSyntheticsContainer()->GetExact( + ConstString(spec.GetName()), children_sp)); else - m_opaque_sp->GetTypeSyntheticsContainer()->GetExact( - ConstString(spec.GetName()), children_sp); + FormatDropExpected(m_opaque_sp->GetTypeSyntheticsContainer()->GetExact( + ConstString(spec.GetName()), children_sp)); if (!children_sp) return LLDB_RECORD_RESULT(lldb::SBTypeSynthetic()); Index: lldb/source/DataFormatters/FormatClasses.cpp =================================================================== --- lldb/source/DataFormatters/FormatClasses.cpp +++ lldb/source/DataFormatters/FormatClasses.cpp @@ -47,3 +47,34 @@ lldb::DynamicValueType FormattersMatchData::GetDynamicValueType() { return m_dynamic_value_type; } + +char FormatDupError::ID = 0; + +FormatDupError::FormatDupError(RegularExpressionSP regex1, + RegularExpressionSP regex2, ConstString str) + : m_regex1(std::move(regex1)), m_regex2(std::move(regex2)), m_str(str) {} + +void FormatDupError::log(llvm::raw_ostream &OS) const { + OS << llvm::formatv("Two regexes (\"{0}\" and \"{1}\") ambiguously match the " + "same string \"{2}\".", + m_regex1->GetText(), m_regex2->GetText(), m_str); +} +std::error_code FormatDupError::convertToErrorCode() const { + return llvm::inconvertibleErrorCode(); +} + +/// FormatDropExpected returns whether function succeeded, dropping the error +/// code even if it failed. Call ValueObject::TakeError() if possible. +/// +/// \param e confusingly evaluates as true even if it is a false return from +// function: +/// | retval && *retval | true return. | +/// | retval && !*retval | false return with no error code reported. | +/// | !retval | false return with error code retval.takeError(). | +bool lldb_private::FormatDropExpected(llvm::Expected &&e) { + if (e) + return *e; + llvm::handleAllErrors(e.takeError(), + [&](std::unique_ptr E) {}); + return false; +} Index: lldb/source/DataFormatters/TypeCategory.cpp =================================================================== --- lldb/source/DataFormatters/TypeCategory.cpp +++ lldb/source/DataFormatters/TypeCategory.cpp @@ -101,12 +101,22 @@ lldb::TypeFormatImplSP &entry, uint32_t *reason) { if (!IsEnabled() || !IsApplicable(valobj)) return false; - if (GetTypeFormatsContainer()->Get(candidates, entry, reason)) + llvm::Expected plain = + GetTypeFormatsContainer()->Get(candidates, entry, reason); + if (plain && *plain) return true; - bool regex = GetRegexTypeFormatsContainer()->Get(candidates, entry, reason); - if (regex && reason) - *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; - return regex; + llvm::Expected regex = + GetRegexTypeFormatsContainer()->Get(candidates, entry, reason); + if (regex && *regex) { + FormatDropExpected(std::move(plain)); + if (reason) + *reason |= + lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; + return true; + } + valobj.TakeError(std::move(plain)); + valobj.TakeError(std::move(regex)); + return false; } bool TypeCategoryImpl::Get(ValueObject &valobj, @@ -114,12 +124,22 @@ lldb::TypeSummaryImplSP &entry, uint32_t *reason) { if (!IsEnabled() || !IsApplicable(valobj)) return false; - if (GetTypeSummariesContainer()->Get(candidates, entry, reason)) + llvm::Expected plain = + GetTypeSummariesContainer()->Get(candidates, entry, reason); + if (plain && *plain) + return true; + llvm::Expected regex = + GetRegexTypeSummariesContainer()->Get(candidates, entry, reason); + if (regex && *regex) { + FormatDropExpected(std::move(plain)); + if (reason) + *reason |= + lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return true; - bool regex = GetRegexTypeSummariesContainer()->Get(candidates, entry, reason); - if (regex && reason) - *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; - return regex; + } + valobj.TakeError(std::move(plain)); + valobj.TakeError(std::move(regex)); + return false; } bool TypeCategoryImpl::Get(ValueObject &valobj, @@ -132,20 +152,38 @@ bool regex_filter = false; // first find both Filter and Synth, and then check which is most recent - if (!GetTypeFiltersContainer()->Get(candidates, filter_sp, &reason_filter)) - regex_filter = GetRegexTypeFiltersContainer()->Get(candidates, filter_sp, - &reason_filter); + llvm::Expected error_filter_regex(false); + llvm::Expected error_filter_plain = + GetTypeFiltersContainer()->Get(candidates, filter_sp, &reason_filter); + if (!error_filter_plain || !*error_filter_plain) { + FormatDropExpected(std::move(error_filter_regex)); + error_filter_regex = GetRegexTypeFiltersContainer()->Get( + candidates, filter_sp, &reason_filter); + if (error_filter_regex && *error_filter_regex) + regex_filter = true; + } bool regex_synth = false; uint32_t reason_synth = 0; bool pick_synth = false; ScriptedSyntheticChildren::SharedPointer synth; - if (!GetTypeSyntheticsContainer()->Get(candidates, synth, &reason_synth)) - regex_synth = GetRegexTypeSyntheticsContainer()->Get(candidates, synth, - &reason_synth); - if (!filter_sp.get() && !synth.get()) + llvm::Expected error_synth_regex(false); + llvm::Expected error_synth_plain = + GetTypeSyntheticsContainer()->Get(candidates, synth, &reason_synth); + if (!error_synth_plain || !*error_synth_plain) { + FormatDropExpected(std::move(error_synth_regex)); + error_synth_regex = GetRegexTypeSyntheticsContainer()->Get( + candidates, synth, &reason_synth); + if (error_synth_regex && *error_synth_regex) + regex_synth = true; + } + if (!filter_sp.get() && !synth.get()) { + valobj.TakeError(std::move(error_filter_plain)); + valobj.TakeError(std::move(error_filter_regex)); + valobj.TakeError(std::move(error_synth_plain)); + valobj.TakeError(std::move(error_synth_regex)); return false; - else if (!filter_sp.get() && synth.get()) + } else if (!filter_sp.get() && synth.get()) pick_synth = true; else if (filter_sp.get() && !synth.get()) @@ -155,18 +193,22 @@ { pick_synth = filter_sp->GetRevision() <= synth->GetRevision(); } + + FormatDropExpected(std::move(error_filter_plain)); + FormatDropExpected(std::move(error_filter_regex)); + FormatDropExpected(std::move(error_synth_plain)); + FormatDropExpected(std::move(error_synth_regex)); + if (pick_synth) { if (regex_synth && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter; entry = synth; - return true; } else { if (regex_filter && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter; entry = filter_sp; - return true; } - return false; + return true; } bool TypeCategoryImpl::Get(ValueObject &valobj, @@ -174,13 +216,22 @@ lldb::TypeValidatorImplSP &entry, uint32_t *reason) { if (!IsEnabled()) return false; - if (GetTypeValidatorsContainer()->Get(candidates, entry, reason)) + llvm::Expected plain = + GetTypeValidatorsContainer()->Get(candidates, entry, reason); + if (plain && *plain) return true; - bool regex = + llvm::Expected regex = GetRegexTypeValidatorsContainer()->Get(candidates, entry, reason); - if (regex && reason) - *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; - return regex; + if (regex && *regex) { + FormatDropExpected(std::move(plain)); + if (reason) + *reason |= + lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; + return true; + } + valobj.TakeError(std::move(plain)); + valobj.TakeError(std::move(regex)); + return false; } void TypeCategoryImpl::Clear(FormatCategoryItems items) { @@ -295,7 +346,8 @@ TypeValidatorImpl::SharedPointer validator_sp; if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue) { - if (GetTypeFormatsContainer()->Get(type_name, format_sp)) { + if (FormatDropExpected( + GetTypeFormatsContainer()->Get(type_name, format_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -305,7 +357,8 @@ } if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue) { - if (GetRegexTypeFormatsContainer()->Get(type_name, format_sp)) { + if (FormatDropExpected( + GetRegexTypeFormatsContainer()->Get(type_name, format_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -315,7 +368,8 @@ } if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary) { - if (GetTypeSummariesContainer()->Get(type_name, summary_sp)) { + if (FormatDropExpected( + GetTypeSummariesContainer()->Get(type_name, summary_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -325,7 +379,8 @@ } if ((items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary) { - if (GetRegexTypeSummariesContainer()->Get(type_name, summary_sp)) { + if (FormatDropExpected( + GetRegexTypeSummariesContainer()->Get(type_name, summary_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -335,7 +390,8 @@ } if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter) { - if (GetTypeFiltersContainer()->Get(type_name, filter_sp)) { + if (FormatDropExpected( + GetTypeFiltersContainer()->Get(type_name, filter_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -345,7 +401,8 @@ } if ((items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter) { - if (GetRegexTypeFiltersContainer()->Get(type_name, filter_sp)) { + if (FormatDropExpected( + GetRegexTypeFiltersContainer()->Get(type_name, filter_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -355,7 +412,8 @@ } if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth) { - if (GetTypeSyntheticsContainer()->Get(type_name, synth_sp)) { + if (FormatDropExpected( + GetTypeSyntheticsContainer()->Get(type_name, synth_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -365,7 +423,8 @@ } if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth) { - if (GetRegexTypeSyntheticsContainer()->Get(type_name, synth_sp)) { + if (FormatDropExpected( + GetRegexTypeSyntheticsContainer()->Get(type_name, synth_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -375,7 +434,8 @@ } if ((items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator) { - if (GetTypeValidatorsContainer()->Get(type_name, validator_sp)) { + if (FormatDropExpected( + GetTypeValidatorsContainer()->Get(type_name, validator_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -385,7 +445,8 @@ } if ((items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator) { - if (GetRegexTypeValidatorsContainer()->Get(type_name, validator_sp)) { + if (FormatDropExpected( + GetRegexTypeValidatorsContainer()->Get(type_name, validator_sp))) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) @@ -403,11 +464,11 @@ if (type_sp) { if (type_sp->IsRegex()) - GetRegexTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()), - retval); + FormatDropExpected(GetRegexTypeFormatsContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); else - GetTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()), - retval); + FormatDropExpected(GetTypeFormatsContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); } return retval; @@ -419,11 +480,11 @@ if (type_sp) { if (type_sp->IsRegex()) - GetRegexTypeSummariesContainer()->GetExact( - ConstString(type_sp->GetName()), retval); + FormatDropExpected(GetRegexTypeSummariesContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); else - GetTypeSummariesContainer()->GetExact(ConstString(type_sp->GetName()), - retval); + FormatDropExpected(GetTypeSummariesContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); } return retval; @@ -435,11 +496,11 @@ if (type_sp) { if (type_sp->IsRegex()) - GetRegexTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()), - retval); + FormatDropExpected(GetRegexTypeFiltersContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); else - GetTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()), - retval); + FormatDropExpected(GetTypeFiltersContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); } return retval; @@ -451,11 +512,11 @@ if (type_sp) { if (type_sp->IsRegex()) - GetRegexTypeSyntheticsContainer()->GetExact( - ConstString(type_sp->GetName()), retval); + FormatDropExpected(GetRegexTypeSyntheticsContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); else - GetTypeSyntheticsContainer()->GetExact(ConstString(type_sp->GetName()), - retval); + FormatDropExpected(GetTypeSyntheticsContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); } return retval; @@ -467,11 +528,11 @@ if (type_sp) { if (type_sp->IsRegex()) - GetRegexTypeValidatorsContainer()->GetExact( - ConstString(type_sp->GetName()), retval); + FormatDropExpected(GetRegexTypeValidatorsContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); else - GetTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()), - retval); + FormatDropExpected(GetTypeValidatorsContainer()->GetExact( + ConstString(type_sp->GetName()), retval)); } return retval;