//===-- TypeCategory.cpp -----------------------------------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/DataFormatters/TypeCategory.h" #include "lldb/Target/Language.h" using namespace lldb; using namespace lldb_private; TypeCategoryImpl::TypeCategoryImpl( IFormatChangeListener *clist, ConstString name, std::initializer_list langs) : m_format_cont("format", "regex-format", clist), m_summary_cont("summary", "regex-summary", clist), m_filter_cont("filter", "regex-filter", clist), m_synth_cont("synth", "regex-synth", clist), m_validator_cont("validator", "regex-validator", clist), m_enabled(false), m_change_listener(clist), m_mutex(), m_name(name), m_languages() { for (const lldb::LanguageType lang : langs) AddLanguage(lang); } static bool IsApplicable(lldb::LanguageType category_lang, lldb::LanguageType valobj_lang) { switch (category_lang) { // Unless we know better, allow only exact equality. default: return category_lang == valobj_lang; // the C family, we consider it as one case eLanguageTypeC89: case eLanguageTypeC: case eLanguageTypeC99: return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC || valobj_lang == eLanguageTypeC99; // ObjC knows about C and itself case eLanguageTypeObjC: return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC || valobj_lang == eLanguageTypeC99 || valobj_lang == eLanguageTypeObjC; // C++ knows about C and C++ case eLanguageTypeC_plus_plus: return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC || valobj_lang == eLanguageTypeC99 || valobj_lang == eLanguageTypeC_plus_plus; // ObjC++ knows about C,C++,ObjC and ObjC++ case eLanguageTypeObjC_plus_plus: return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC || valobj_lang == eLanguageTypeC99 || valobj_lang == eLanguageTypeC_plus_plus || valobj_lang == eLanguageTypeObjC; // Categories with unspecified language match everything. case eLanguageTypeUnknown: return true; } } bool TypeCategoryImpl::IsApplicable(ValueObject &valobj) { lldb::LanguageType valobj_lang = valobj.GetObjectRuntimeLanguage(); for (size_t idx = 0; idx < GetNumLanguages(); idx++) { const lldb::LanguageType category_lang = GetLanguageAtIndex(idx); if (::IsApplicable(category_lang, valobj_lang)) return true; } return false; } size_t TypeCategoryImpl::GetNumLanguages() { if (m_languages.empty()) return 1; return m_languages.size(); } lldb::LanguageType TypeCategoryImpl::GetLanguageAtIndex(size_t idx) { if (m_languages.empty()) return lldb::eLanguageTypeUnknown; return m_languages[idx]; } void TypeCategoryImpl::AddLanguage(lldb::LanguageType lang) { m_languages.push_back(lang); } bool TypeCategoryImpl::HasLanguage(lldb::LanguageType lang) { const auto iter = std::find(m_languages.begin(), m_languages.end(), lang), end = m_languages.end(); return (iter != end); } bool TypeCategoryImpl::Get(ValueObject &valobj, const FormattersMatchVector &candidates, lldb::TypeFormatImplSP &entry, uint32_t *reason) { if (!IsEnabled() || !IsApplicable(valobj)) return false; if (GetTypeFormatsContainer()->Get(candidates, entry, reason)) return true; bool regex = GetRegexTypeFormatsContainer()->Get(candidates, entry, reason); if (regex && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return regex; } bool TypeCategoryImpl::Get(ValueObject &valobj, const FormattersMatchVector &candidates, lldb::TypeSummaryImplSP &entry, uint32_t *reason) { if (!IsEnabled() || !IsApplicable(valobj)) return false; if (GetTypeSummariesContainer()->Get(candidates, entry, reason)) return true; bool regex = GetRegexTypeSummariesContainer()->Get(candidates, entry, reason); if (regex && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return regex; } bool TypeCategoryImpl::Get(ValueObject &valobj, const FormattersMatchVector &candidates, lldb::SyntheticChildrenSP &entry, uint32_t *reason) { if (!IsEnabled() || !IsApplicable(valobj)) return false; TypeFilterImpl::SharedPointer filter_sp; uint32_t reason_filter = 0; 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); 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()) return false; else if (!filter_sp.get() && synth.get()) pick_synth = true; else if (filter_sp.get() && !synth.get()) pick_synth = false; else /*if (filter_sp.get() && synth.get())*/ { pick_synth = filter_sp->GetRevision() <= synth->GetRevision(); } 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; } bool TypeCategoryImpl::Get(ValueObject &valobj, const FormattersMatchVector &candidates, lldb::TypeValidatorImplSP &entry, uint32_t *reason) { if (!IsEnabled()) return false; if (GetTypeValidatorsContainer()->Get(candidates, entry, reason)) return true; bool regex = GetRegexTypeValidatorsContainer()->Get(candidates, entry, reason); if (regex && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return regex; } void TypeCategoryImpl::Clear(FormatCategoryItems items) { if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue) GetTypeFormatsContainer()->Clear(); if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue) GetRegexTypeFormatsContainer()->Clear(); if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary) GetTypeSummariesContainer()->Clear(); if ((items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary) GetRegexTypeSummariesContainer()->Clear(); if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter) GetTypeFiltersContainer()->Clear(); if ((items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter) GetRegexTypeFiltersContainer()->Clear(); if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth) GetTypeSyntheticsContainer()->Clear(); if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth) GetRegexTypeSyntheticsContainer()->Clear(); if ((items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator) GetTypeValidatorsContainer()->Clear(); if ((items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator) GetRegexTypeValidatorsContainer()->Clear(); } bool TypeCategoryImpl::Delete(ConstString name, FormatCategoryItems items) { bool success = false; if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue) success = GetTypeFormatsContainer()->Delete(name) || success; if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue) success = GetRegexTypeFormatsContainer()->Delete(name) || success; if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary) success = GetTypeSummariesContainer()->Delete(name) || success; if ((items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary) success = GetRegexTypeSummariesContainer()->Delete(name) || success; if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter) success = GetTypeFiltersContainer()->Delete(name) || success; if ((items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter) success = GetRegexTypeFiltersContainer()->Delete(name) || success; if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth) success = GetTypeSyntheticsContainer()->Delete(name) || success; if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth) success = GetRegexTypeSyntheticsContainer()->Delete(name) || success; if ((items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator) success = GetTypeValidatorsContainer()->Delete(name) || success; if ((items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator) success = GetRegexTypeValidatorsContainer()->Delete(name) || success; return success; } uint32_t TypeCategoryImpl::GetCount(FormatCategoryItems items) { uint32_t count = 0; if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue) count += GetTypeFormatsContainer()->GetCount(); if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue) count += GetRegexTypeFormatsContainer()->GetCount(); if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary) count += GetTypeSummariesContainer()->GetCount(); if ((items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary) count += GetRegexTypeSummariesContainer()->GetCount(); if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter) count += GetTypeFiltersContainer()->GetCount(); if ((items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter) count += GetRegexTypeFiltersContainer()->GetCount(); if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth) count += GetTypeSyntheticsContainer()->GetCount(); if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth) count += GetRegexTypeSyntheticsContainer()->GetCount(); if ((items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator) count += GetTypeValidatorsContainer()->GetCount(); if ((items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator) count += GetRegexTypeValidatorsContainer()->GetCount(); return count; } bool TypeCategoryImpl::AnyMatches(ConstString type_name, FormatCategoryItems items, bool only_enabled, const char **matching_category, FormatCategoryItems *matching_type) { if (!IsEnabled() && only_enabled) return false; lldb::TypeFormatImplSP format_sp; lldb::TypeSummaryImplSP summary_sp; TypeFilterImpl::SharedPointer filter_sp; ScriptedSyntheticChildren::SharedPointer synth_sp; TypeValidatorImpl::SharedPointer validator_sp; if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue) { if (GetTypeFormatsContainer()->Get(type_name, format_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemValue; return true; } } if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue) { if (GetRegexTypeFormatsContainer()->Get(type_name, format_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemRegexValue; return true; } } if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary) { if (GetTypeSummariesContainer()->Get(type_name, summary_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemSummary; return true; } } if ((items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary) { if (GetRegexTypeSummariesContainer()->Get(type_name, summary_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemRegexSummary; return true; } } if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter) { if (GetTypeFiltersContainer()->Get(type_name, filter_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemFilter; return true; } } if ((items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter) { if (GetRegexTypeFiltersContainer()->Get(type_name, filter_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemRegexFilter; return true; } } if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth) { if (GetTypeSyntheticsContainer()->Get(type_name, synth_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemSynth; return true; } } if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth) { if (GetRegexTypeSyntheticsContainer()->Get(type_name, synth_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemRegexSynth; return true; } } if ((items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator) { if (GetTypeValidatorsContainer()->Get(type_name, validator_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemValidator; return true; } } if ((items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator) { if (GetRegexTypeValidatorsContainer()->Get(type_name, validator_sp)) { if (matching_category) *matching_category = m_name.GetCString(); if (matching_type) *matching_type = eFormatCategoryItemRegexValidator; return true; } } return false; } TypeCategoryImpl::FormatContainer::MapValueType TypeCategoryImpl::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) { FormatContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) GetRegexTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()), retval); else GetTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()), retval); } return retval; } TypeCategoryImpl::SummaryContainer::MapValueType TypeCategoryImpl::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) { SummaryContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) GetRegexTypeSummariesContainer()->GetExact( ConstString(type_sp->GetName()), retval); else GetTypeSummariesContainer()->GetExact(ConstString(type_sp->GetName()), retval); } return retval; } TypeCategoryImpl::FilterContainer::MapValueType TypeCategoryImpl::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) { FilterContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) GetRegexTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()), retval); else GetTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()), retval); } return retval; } TypeCategoryImpl::SynthContainer::MapValueType TypeCategoryImpl::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) { SynthContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) GetRegexTypeSyntheticsContainer()->GetExact( ConstString(type_sp->GetName()), retval); else GetTypeSyntheticsContainer()->GetExact(ConstString(type_sp->GetName()), retval); } return retval; } TypeCategoryImpl::ValidatorContainer::MapValueType TypeCategoryImpl::GetValidatorForType(lldb::TypeNameSpecifierImplSP type_sp) { ValidatorContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) GetRegexTypeValidatorsContainer()->GetExact( ConstString(type_sp->GetName()), retval); else GetTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()), retval); } return retval; } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex(size_t index) { if (index < GetTypeSummariesContainer()->GetCount()) return GetTypeSummariesContainer()->GetTypeNameSpecifierAtIndex(index); else return GetRegexTypeSummariesContainer()->GetTypeNameSpecifierAtIndex( index - GetTypeSummariesContainer()->GetCount()); } TypeCategoryImpl::FormatContainer::MapValueType TypeCategoryImpl::GetFormatAtIndex(size_t index) { if (index < GetTypeFormatsContainer()->GetCount()) return GetTypeFormatsContainer()->GetAtIndex(index); else return GetRegexTypeFormatsContainer()->GetAtIndex( index - GetTypeFormatsContainer()->GetCount()); } TypeCategoryImpl::SummaryContainer::MapValueType TypeCategoryImpl::GetSummaryAtIndex(size_t index) { if (index < GetTypeSummariesContainer()->GetCount()) return GetTypeSummariesContainer()->GetAtIndex(index); else return GetRegexTypeSummariesContainer()->GetAtIndex( index - GetTypeSummariesContainer()->GetCount()); } TypeCategoryImpl::FilterContainer::MapValueType TypeCategoryImpl::GetFilterAtIndex(size_t index) { if (index < GetTypeFiltersContainer()->GetCount()) return GetTypeFiltersContainer()->GetAtIndex(index); else return GetRegexTypeFiltersContainer()->GetAtIndex( index - GetTypeFiltersContainer()->GetCount()); } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForFormatAtIndex(size_t index) { if (index < GetTypeFormatsContainer()->GetCount()) return GetTypeFormatsContainer()->GetTypeNameSpecifierAtIndex(index); else return GetRegexTypeFormatsContainer()->GetTypeNameSpecifierAtIndex( index - GetTypeFormatsContainer()->GetCount()); } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForFilterAtIndex(size_t index) { if (index < GetTypeFiltersContainer()->GetCount()) return GetTypeFiltersContainer()->GetTypeNameSpecifierAtIndex(index); else return GetRegexTypeFiltersContainer()->GetTypeNameSpecifierAtIndex( index - GetTypeFiltersContainer()->GetCount()); } TypeCategoryImpl::SynthContainer::MapValueType TypeCategoryImpl::GetSyntheticAtIndex(size_t index) { if (index < GetTypeSyntheticsContainer()->GetCount()) return GetTypeSyntheticsContainer()->GetAtIndex(index); else return GetRegexTypeSyntheticsContainer()->GetAtIndex( index - GetTypeSyntheticsContainer()->GetCount()); } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex(size_t index) { if (index < GetTypeSyntheticsContainer()->GetCount()) return GetTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex(index); else return GetRegexTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex( index - GetTypeSyntheticsContainer()->GetCount()); } TypeCategoryImpl::ValidatorContainer::MapValueType TypeCategoryImpl::GetValidatorAtIndex(size_t index) { if (index < GetTypeValidatorsContainer()->GetCount()) return GetTypeValidatorsContainer()->GetAtIndex(index); else return GetRegexTypeValidatorsContainer()->GetAtIndex( index - GetTypeValidatorsContainer()->GetCount()); } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForValidatorAtIndex(size_t index) { if (index < GetTypeValidatorsContainer()->GetCount()) return GetTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex(index); else return GetRegexTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex( index - GetTypeValidatorsContainer()->GetCount()); } void TypeCategoryImpl::Enable(bool value, uint32_t position) { std::lock_guard guard(m_mutex); if ((m_enabled = value)) m_enabled_position = position; if (m_change_listener) m_change_listener->Changed(); } std::string TypeCategoryImpl::GetDescription() { StreamString stream; stream.Printf("%s (%s", GetName(), (IsEnabled() ? "enabled" : "disabled")); StreamString lang_stream; lang_stream.Printf(", applicable for language(s): "); bool print_lang = false; for (size_t idx = 0; idx < GetNumLanguages(); idx++) { const lldb::LanguageType lang = GetLanguageAtIndex(idx); if (lang != lldb::eLanguageTypeUnknown) print_lang = true; lang_stream.Printf("%s%s", Language::GetNameForLanguageType(lang), idx + 1 < GetNumLanguages() ? ", " : ""); } if (print_lang) stream.PutCString(lang_stream.GetString()); stream.PutChar(')'); return stream.GetString(); }