Sent you https://reviews.llvm.org/D137000 for review :)
On Wed, Oct 19, 2022 at 2:16 PM Jorge Gorbe Moya <jgo...@google.com> wrote: > Hi Jim, > > Thanks for the encouragement! It's unfortunate that you missed the > notifications and couldn't contribute to the code reviews, but I'm glad you > think the code looks fine. > > Of course I don't mind adding these as a follow-up, it would be a shame if > I didn't expose the new feature for CLI users after doing all the work > to get to this point. In fact, I was planning to ask about it after landing > the change, so thank you for the details about how to proceed next :) > > On Wed, Oct 19, 2022 at 2:00 PM Jim Ingham <jing...@apple.com> wrote: > >> Jorge, >> >> It's great to see you worked your way through this change! >> >> Something in our mail pipeline is dropping all my lldb-commits and review >> comment notifications. Still haven't figured out who is doing that, so I >> didn't get a chance to look over the final version. >> >> The code looks fine, but nobody will know how to use this if they don't >> read lldb source code fairly carefully, or browse our tests. >> >> To finish off the feature, there should be an example to put in the >> examples directory, and there should be a paragraph showing how to use it >> in lldb/doc/use/formatting.rst. >> >> It would also be good to add something an option to "type summary add" >> and "type synthetic add" to indicate that the name passed is neither a type >> name nor a regex but a recognizer function instead. Maybe >> -R/--recognizer-function? >> >> Is it too horrible of me to ask you to do these as a follow-up? >> Otherwise I fear you will be the only one to use this feature... >> >> Jim >> >> >> > On Oct 19, 2022, at 12:54 PM, Jorge Gorbe Moya via lldb-commits < >> lldb-commits@lists.llvm.org> wrote: >> > >> > >> > Author: Jorge Gorbe Moya >> > Date: 2022-10-19T12:53:38-07:00 >> > New Revision: d76566417e592cfac9c710f82575473b1b4a9285 >> > >> > URL: >> https://github.com/llvm/llvm-project/commit/d76566417e592cfac9c710f82575473b1b4a9285 >> > DIFF: >> https://github.com/llvm/llvm-project/commit/d76566417e592cfac9c710f82575473b1b4a9285.diff >> > >> > LOG: [lldb] Add matching based on Python callbacks for data formatters. >> > >> > This patch adds a new matching method for data formatters, in addition >> > to the existing exact typename and regex-based matching. The new method >> > allows users to specify the name of a Python callback function that >> > takes a `SBType` object and decides whether the type is a match or not. >> > >> > Here is an overview of the changes performed: >> > >> > - Add a new `eFormatterMatchCallback` matching type, and logic to handle >> > it in `TypeMatcher` and `SBTypeNameSpecifier`. >> > >> > - Extend `FormattersMatchCandidate` instances with a pointer to the >> > current `ScriptInterpreter` and the `TypeImpl` corresponding to the >> > candidate type, so we can run registered callbacks and pass the type >> > to them. All matcher search functions now receive a >> > `FormattersMatchCandidate` instead of a type name. >> > >> > - Add some glue code to ScriptInterpreterPython and the SWIG bindings to >> > allow calling a formatter matching callback. Most of this code is >> > modeled after the equivalent code for watchpoint callback functions. >> > >> > - Add an API test for the new callback-based matching feature. >> > >> > For more context, please check the RFC thread where this feature was >> > originally discussed: >> > >> https://discourse.llvm.org/t/rfc-python-callback-for-data-formatters-type-matching/64204/11 >> > >> > Differential Revision: https://reviews.llvm.org/D135648 >> > >> > Added: >> > >> lldb/test/API/functionalities/data-formatter/callback-matching/Makefile >> > >> lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py >> > >> lldb/test/API/functionalities/data-formatter/callback-matching/formatters_with_callback.py >> > >> lldb/test/API/functionalities/data-formatter/callback-matching/main.cpp >> > >> > Modified: >> > lldb/bindings/python/python-swigsafecast.swig >> > lldb/bindings/python/python-wrapper.swig >> > lldb/include/lldb/API/SBType.h >> > lldb/include/lldb/DataFormatters/DataVisualization.h >> > lldb/include/lldb/DataFormatters/FormatClasses.h >> > lldb/include/lldb/DataFormatters/FormatManager.h >> > lldb/include/lldb/DataFormatters/FormattersContainer.h >> > lldb/include/lldb/DataFormatters/TypeCategory.h >> > lldb/include/lldb/DataFormatters/TypeCategoryMap.h >> > lldb/include/lldb/Interpreter/ScriptInterpreter.h >> > lldb/include/lldb/Target/Language.h >> > lldb/include/lldb/lldb-enumerations.h >> > lldb/source/API/SBTypeNameSpecifier.cpp >> > lldb/source/Commands/CommandObjectType.cpp >> > lldb/source/DataFormatters/DataVisualization.cpp >> > lldb/source/DataFormatters/FormatManager.cpp >> > lldb/source/DataFormatters/TypeCategory.cpp >> > lldb/source/DataFormatters/TypeCategoryMap.cpp >> > lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp >> > lldb/source/Plugins/Language/ObjC/ObjCLanguage.h >> > lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h >> > >> lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp >> > >> lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h >> > lldb/source/Target/Language.cpp >> > lldb/unittests/DataFormatter/FormattersContainerTest.cpp >> > lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp >> > >> > Removed: >> > >> > >> > >> > >> ################################################################################ >> > diff --git a/lldb/bindings/python/python-swigsafecast.swig >> b/lldb/bindings/python/python-swigsafecast.swig >> > index eb684133abef..aa5e8e50a2d9 100644 >> > --- a/lldb/bindings/python/python-swigsafecast.swig >> > +++ b/lldb/bindings/python/python-swigsafecast.swig >> > @@ -97,6 +97,10 @@ PythonObject >> ToSWIGWrapper(lldb::ExecutionContextRefSP ctx_sp) { >> > SWIGTYPE_p_lldb__SBExecutionContext); >> > } >> > >> > +PythonObject ToSWIGWrapper(lldb::TypeImplSP type_impl_sp) { >> > + return ToSWIGHelper(new lldb::SBType(type_impl_sp), >> SWIGTYPE_p_lldb__SBType); >> > +} >> > + >> > PythonObject ToSWIGWrapper(const TypeSummaryOptions &summary_options) { >> > return ToSWIGHelper(new lldb::SBTypeSummaryOptions(summary_options), >> > SWIGTYPE_p_lldb__SBTypeSummaryOptions); >> > >> > diff --git a/lldb/bindings/python/python-wrapper.swig >> b/lldb/bindings/python/python-wrapper.swig >> > index 626fc47bebb9..adac8a405ab9 100644 >> > --- a/lldb/bindings/python/python-wrapper.swig >> > +++ b/lldb/bindings/python/python-wrapper.swig >> > @@ -90,6 +90,32 @@ bool >> lldb_private::LLDBSwigPythonWatchpointCallbackFunction( >> > return stop_at_watchpoint; >> > } >> > >> > +// This function is called by >> > +// ScriptInterpreterPython::FormatterMatchingCallbackFunction and it's >> used when >> > +// a data formatter provides the name of a callback to inspect a >> candidate type >> > +// before considering a match. >> > +bool lldb_private::LLDBSwigPythonFormatterCallbackFunction( >> > + const char *python_function_name, const char >> *session_dictionary_name, >> > + lldb::TypeImplSP type_impl_sp) { >> > + >> > + PyErr_Cleaner py_err_cleaner(true); >> > + >> > + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( >> > + session_dictionary_name); >> > + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( >> > + python_function_name, dict); >> > + >> > + if (!pfunc.IsAllocated()) >> > + return false; >> > + >> > + PythonObject result = >> > + pfunc(ToSWIGWrapper(type_impl_sp), dict); >> > + >> > + // Only if everything goes okay and the function returns True we'll >> consider >> > + // it a match. >> > + return result.get() == Py_True; >> > +} >> > + >> > bool lldb_private::LLDBSwigPythonCallTypeScript( >> > const char *python_function_name, const void *session_dictionary, >> > const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper, >> > >> > diff --git a/lldb/include/lldb/API/SBType.h >> b/lldb/include/lldb/API/SBType.h >> > index aa45aeeec476..215e03fad99b 100644 >> > --- a/lldb/include/lldb/API/SBType.h >> > +++ b/lldb/include/lldb/API/SBType.h >> > @@ -106,6 +106,7 @@ class SBType { >> > SBType(); >> > >> > SBType(const lldb::SBType &rhs); >> > + SBType(const lldb::TypeImplSP &); >> > >> > ~SBType(); >> > >> > @@ -239,7 +240,6 @@ class SBType { >> > >> > SBType(const lldb_private::CompilerType &); >> > SBType(const lldb::TypeSP &); >> > - SBType(const lldb::TypeImplSP &); >> > }; >> > >> > class SBTypeList { >> > >> > diff --git a/lldb/include/lldb/DataFormatters/DataVisualization.h >> b/lldb/include/lldb/DataFormatters/DataVisualization.h >> > index 7be07d65acdd..5aea29132b8f 100644 >> > --- a/lldb/include/lldb/DataFormatters/DataVisualization.h >> > +++ b/lldb/include/lldb/DataFormatters/DataVisualization.h >> > @@ -51,7 +51,7 @@ class DataVisualization { >> > GetSyntheticChildren(ValueObject &valobj, lldb::DynamicValueType >> use_dynamic); >> > >> > static bool >> > - AnyMatches(ConstString type_name, >> > + AnyMatches(const FormattersMatchCandidate &candidate_type, >> > TypeCategoryImpl::FormatCategoryItems items = >> > TypeCategoryImpl::ALL_ITEM_TYPES, >> > bool only_enabled = true, const char **matching_category = >> nullptr, >> > >> > diff --git a/lldb/include/lldb/DataFormatters/FormatClasses.h >> b/lldb/include/lldb/DataFormatters/FormatClasses.h >> > index ac2b070a55cd..a6bc3a354253 100644 >> > --- a/lldb/include/lldb/DataFormatters/FormatClasses.h >> > +++ b/lldb/include/lldb/DataFormatters/FormatClasses.h >> > @@ -17,6 +17,7 @@ >> > #include "lldb/DataFormatters/TypeFormat.h" >> > #include "lldb/DataFormatters/TypeSummary.h" >> > #include "lldb/DataFormatters/TypeSynthetic.h" >> > +#include "lldb/Interpreter/ScriptInterpreter.h" >> > #include "lldb/Symbol/CompilerType.h" >> > #include "lldb/Symbol/Type.h" >> > #include "lldb/lldb-enumerations.h" >> > @@ -73,13 +74,22 @@ class FormattersMatchCandidate { >> > } >> > }; >> > >> > - FormattersMatchCandidate(ConstString name, Flags flags) >> > - : m_type_name(name), m_flags(flags) {} >> > + FormattersMatchCandidate(ConstString name, >> > + ScriptInterpreter *script_interpreter, >> TypeImpl type, >> > + Flags flags) >> > + : m_type_name(name), m_script_interpreter(script_interpreter), >> > + m_type(type), m_flags(flags) {} >> > >> > ~FormattersMatchCandidate() = default; >> > >> > ConstString GetTypeName() const { return m_type_name; } >> > >> > + TypeImpl GetType() const { return m_type; } >> > + >> > + ScriptInterpreter *GetScriptInterpreter() const { >> > + return m_script_interpreter; >> > + } >> > + >> > bool DidStripPointer() const { return m_flags.stripped_pointer; } >> > >> > bool DidStripReference() const { return m_flags.stripped_reference; } >> > @@ -101,6 +111,10 @@ class FormattersMatchCandidate { >> > >> > private: >> > ConstString m_type_name; >> > + // If a formatter provides a matching callback function, we need the >> script >> > + // interpreter and the type object (as an argument to the callback). >> > + ScriptInterpreter *m_script_interpreter; >> > + TypeImpl m_type; >> > Flags m_flags; >> > }; >> > >> > >> > diff --git a/lldb/include/lldb/DataFormatters/FormatManager.h >> b/lldb/include/lldb/DataFormatters/FormatManager.h >> > index 594addd1f083..295d3b84342a 100644 >> > --- a/lldb/include/lldb/DataFormatters/FormatManager.h >> > +++ b/lldb/include/lldb/DataFormatters/FormatManager.h >> > @@ -128,12 +128,12 @@ class FormatManager : public >> IFormatChangeListener { >> > GetSyntheticChildren(ValueObject &valobj, lldb::DynamicValueType >> use_dynamic); >> > >> > bool >> > - AnyMatches(ConstString type_name, >> > + AnyMatches(const FormattersMatchCandidate &candidate_type, >> > TypeCategoryImpl::FormatCategoryItems items = >> > TypeCategoryImpl::ALL_ITEM_TYPES, >> > bool only_enabled = true, const char **matching_category = >> nullptr, >> > TypeCategoryImpl::FormatCategoryItems *matching_type = >> nullptr) { >> > - return m_categories_map.AnyMatches(type_name, items, only_enabled, >> > + return m_categories_map.AnyMatches(candidate_type, items, >> only_enabled, >> > matching_category, >> matching_type); >> > } >> > >> > >> > diff --git a/lldb/include/lldb/DataFormatters/FormattersContainer.h >> b/lldb/include/lldb/DataFormatters/FormattersContainer.h >> > index 8a93c0345cbe..fd046e773b69 100644 >> > --- a/lldb/include/lldb/DataFormatters/FormattersContainer.h >> > +++ b/lldb/include/lldb/DataFormatters/FormattersContainer.h >> > @@ -39,12 +39,16 @@ class IFormatChangeListener { >> > >> > /// Class for matching type names. >> > class TypeMatcher { >> > + /// Type name for exact match, or name of the python callback if >> m_match_type >> > + /// is `eFormatterMatchCallback`. >> > + ConstString m_name; >> > RegularExpression m_type_name_regex; >> > - ConstString m_type_name; >> > /// Indicates what kind of matching strategy should be used: >> > - /// - eFormatterMatchExact: match the exact type name in m_type_name. >> > + /// - eFormatterMatchExact: match the exact type name in m_name. >> > /// - eFormatterMatchRegex: match using the RegularExpression object >> > /// `m_type_name_regex` instead. >> > + /// - eFormatterMatchCallback: run the function in m_name to decide >> if a type >> > + /// matches or not. >> > lldb::FormatterMatchType m_match_type; >> > >> > // if the user tries to add formatters for, say, "struct Foo" those >> will not >> > @@ -73,7 +77,7 @@ class TypeMatcher { >> > TypeMatcher() = delete; >> > /// Creates a matcher that accepts any type with exactly the given >> type name. >> > TypeMatcher(ConstString type_name) >> > - : m_type_name(type_name), >> m_match_type(lldb::eFormatterMatchExact) {} >> > + : m_name(type_name), m_match_type(lldb::eFormatterMatchExact) {} >> > /// Creates a matcher that accepts any type matching the given regex. >> > TypeMatcher(RegularExpression regex) >> > : m_type_name_regex(std::move(regex)), >> > @@ -81,27 +85,44 @@ class TypeMatcher { >> > /// Creates a matcher using the matching type and string from the >> given type >> > /// name specifier. >> > TypeMatcher(lldb::TypeNameSpecifierImplSP type_specifier) >> > - : m_type_name(type_specifier->GetName()), >> > + : m_name(type_specifier->GetName()), >> > m_match_type(type_specifier->GetMatchType()) { >> > if (m_match_type == lldb::eFormatterMatchRegex) >> > m_type_name_regex = RegularExpression(type_specifier->GetName()); >> > } >> > >> > - /// True iff this matches the given type name. >> > - bool Matches(ConstString type_name) const { >> > - if (m_match_type == lldb::eFormatterMatchRegex) >> > + /// True iff this matches the given type. >> > + bool Matches(FormattersMatchCandidate candidate_type) const { >> > + ConstString type_name = candidate_type.GetTypeName(); >> > + switch (m_match_type) { >> > + case lldb::eFormatterMatchExact: >> > + return m_name == type_name || >> > + StripTypeName(m_name) == StripTypeName(type_name); >> > + case lldb::eFormatterMatchRegex: >> > return m_type_name_regex.Execute(type_name.GetStringRef()); >> > - return m_type_name == type_name || >> > - StripTypeName(m_type_name) == StripTypeName(type_name); >> > + case lldb::eFormatterMatchCallback: >> > + // CommandObjectType{Synth,Filter}Add tries to prevent the user >> from >> > + // creating both a synthetic child provider and a filter for the >> same type >> > + // in the same category, but we don't have a type object at that >> point, so >> > + // it creates a dummy candidate without type or script >> interpreter. >> > + // Skip callback matching in these cases. >> > + if (candidate_type.GetScriptInterpreter()) >> > + return >> candidate_type.GetScriptInterpreter()->FormatterCallbackFunction( >> > + m_name.AsCString(), >> > + std::make_shared<TypeImpl>(candidate_type.GetType())); >> > + } >> > + return false; >> > } >> > >> > lldb::FormatterMatchType GetMatchType() const { return m_match_type; } >> > >> > /// Returns the underlying match string for this TypeMatcher. >> > ConstString GetMatchString() const { >> > + if (m_match_type == lldb::eFormatterMatchExact) >> > + return StripTypeName(m_name); >> > if (m_match_type == lldb::eFormatterMatchRegex) >> > - return ConstString(m_type_name_regex.GetText()); >> > - return StripTypeName(m_type_name); >> > + return ConstString(m_type_name_regex.GetText()); >> > + return m_name; >> > } >> > >> > /// Returns true if this TypeMatcher and the given one were most >> created by >> > @@ -155,10 +176,11 @@ template <typename ValueType> class >> FormattersContainer { >> > return false; >> > } >> > >> > - bool Get(ConstString type, ValueSP &entry) { >> > + // Finds the first formatter in the container that matches >> `candidate`. >> > + bool Get(FormattersMatchCandidate candidate, ValueSP &entry) { >> > std::lock_guard<std::recursive_mutex> guard(m_map_mutex); >> > for (auto &formatter : llvm::reverse(m_map)) { >> > - if (formatter.first.Matches(type)) { >> > + if (formatter.first.Matches(candidate)) { >> > entry = formatter.second; >> > return true; >> > } >> > @@ -166,9 +188,11 @@ template <typename ValueType> class >> FormattersContainer { >> > return false; >> > } >> > >> > + // Finds the first match between candidate types in `candidates` and >> > + // formatters in this container. >> > bool Get(const FormattersMatchVector &candidates, ValueSP &entry) { >> > for (const FormattersMatchCandidate &candidate : candidates) { >> > - if (Get(candidate.GetTypeName(), entry)) { >> > + if (Get(candidate, entry)) { >> > if (candidate.IsMatch(entry) == false) { >> > entry.reset(); >> > continue; >> > >> > diff --git a/lldb/include/lldb/DataFormatters/TypeCategory.h >> b/lldb/include/lldb/DataFormatters/TypeCategory.h >> > index bad39aa676af..884a27d76e05 100644 >> > --- a/lldb/include/lldb/DataFormatters/TypeCategory.h >> > +++ b/lldb/include/lldb/DataFormatters/TypeCategory.h >> > @@ -105,10 +105,10 @@ template <typename FormatterImpl> class >> TieredFormatterContainer { >> > return false; >> > } >> > >> > - bool AnyMatches(ConstString type_name) { >> > + bool AnyMatches(const FormattersMatchCandidate &candidate) { >> > std::shared_ptr<FormatterImpl> entry; >> > for (auto sc : m_subcontainers) { >> > - if (sc->Get(type_name, entry)) >> > + if (sc->Get(FormattersMatchVector{candidate}, entry)) >> > return true; >> > } >> > return false; >> > @@ -346,7 +346,7 @@ class TypeCategoryImpl { >> > >> > std::string GetDescription(); >> > >> > - bool AnyMatches(ConstString type_name, >> > + bool AnyMatches(const FormattersMatchCandidate &candidate_type, >> > FormatCategoryItems items = ALL_ITEM_TYPES, >> > bool only_enabled = true, >> > const char **matching_category = nullptr, >> > >> > diff --git a/lldb/include/lldb/DataFormatters/TypeCategoryMap.h >> b/lldb/include/lldb/DataFormatters/TypeCategoryMap.h >> > index 45dbb306aa75..d4f7634c90b0 100644 >> > --- a/lldb/include/lldb/DataFormatters/TypeCategoryMap.h >> > +++ b/lldb/include/lldb/DataFormatters/TypeCategoryMap.h >> > @@ -17,6 +17,7 @@ >> > #include "lldb/lldb-enumerations.h" >> > #include "lldb/lldb-public.h" >> > >> > +#include "lldb/DataFormatters/FormatClasses.h" >> > #include "lldb/DataFormatters/FormattersContainer.h" >> > #include "lldb/DataFormatters/TypeCategory.h" >> > >> > @@ -69,7 +70,7 @@ class TypeCategoryMap { >> > lldb::TypeCategoryImplSP GetAtIndex(uint32_t); >> > >> > bool >> > - AnyMatches(ConstString type_name, >> > + AnyMatches(const FormattersMatchCandidate &candidate_type, >> > TypeCategoryImpl::FormatCategoryItems items = >> > TypeCategoryImpl::ALL_ITEM_TYPES, >> > bool only_enabled = true, const char **matching_category = >> nullptr, >> > >> > diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h >> b/lldb/include/lldb/Interpreter/ScriptInterpreter.h >> > index cb3cafaf2ed5..f34ce43e946e 100644 >> > --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h >> > +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h >> > @@ -418,6 +418,14 @@ class ScriptInterpreter : public PluginInterface { >> > return false; >> > } >> > >> > + // Calls the specified formatter matching Python function and >> returns its >> > + // result (true if it's a match, false if we should keep looking for >> a >> > + // matching formatter). >> > + virtual bool FormatterCallbackFunction(const char *function_name, >> > + lldb::TypeImplSP >> type_impl_sp) { >> > + return true; >> > + } >> > + >> > virtual void Clear() { >> > // Clean up any ref counts to SBObjects that might be in global >> variables >> > } >> > >> > diff --git a/lldb/include/lldb/Target/Language.h >> b/lldb/include/lldb/Target/Language.h >> > index fa79aaee0574..89136cc5e0ff 100644 >> > --- a/lldb/include/lldb/Target/Language.h >> > +++ b/lldb/include/lldb/Target/Language.h >> > @@ -175,7 +175,7 @@ class Language : public PluginInterface { >> > virtual HardcodedFormatters::HardcodedSyntheticFinder >> > GetHardcodedSynthetics(); >> > >> > - virtual std::vector<ConstString> >> > + virtual std::vector<FormattersMatchCandidate> >> > GetPossibleFormattersMatches(ValueObject &valobj, >> > lldb::DynamicValueType use_dynamic); >> > >> > >> > diff --git a/lldb/include/lldb/lldb-enumerations.h >> b/lldb/include/lldb/lldb-enumerations.h >> > index 2ac1a74214b4..3ba29a301382 100644 >> > --- a/lldb/include/lldb/lldb-enumerations.h >> > +++ b/lldb/include/lldb/lldb-enumerations.h >> > @@ -835,8 +835,9 @@ enum TemplateArgumentKind { >> > enum FormatterMatchType { >> > eFormatterMatchExact, >> > eFormatterMatchRegex, >> > + eFormatterMatchCallback, >> > >> > - eLastFormatterMatchType = eFormatterMatchRegex, >> > + eLastFormatterMatchType = eFormatterMatchCallback, >> > }; >> > >> > /// Options that can be set for a formatter to alter its behavior. Not >> > >> > diff --git a/lldb/source/API/SBTypeNameSpecifier.cpp >> b/lldb/source/API/SBTypeNameSpecifier.cpp >> > index d1dc2953c9b9..8a6eb086a9b1 100644 >> > --- a/lldb/source/API/SBTypeNameSpecifier.cpp >> > +++ b/lldb/source/API/SBTypeNameSpecifier.cpp >> > @@ -99,10 +99,14 @@ bool SBTypeNameSpecifier::GetDescription( >> > lldb::SBStream &description, lldb::DescriptionLevel >> description_level) { >> > LLDB_INSTRUMENT_VA(this, description, description_level); >> > >> > + lldb::FormatterMatchType match_type = GetMatchType(); >> > + const char *match_type_str = >> > + (match_type == eFormatterMatchExact ? "plain" >> > + : match_type == eFormatterMatchRegex ? "regex" >> > + : "callback"); >> > if (!IsValid()) >> > return false; >> > - description.Printf("SBTypeNameSpecifier(%s,%s)", GetName(), >> > - IsRegex() ? "regex" : "plain"); >> > + description.Printf("SBTypeNameSpecifier(%s,%s)", GetName(), >> match_type_str); >> > return true; >> > } >> > >> > >> > diff --git a/lldb/source/Commands/CommandObjectType.cpp >> b/lldb/source/Commands/CommandObjectType.cpp >> > index 63d3c6979ec3..ccbe7922e65f 100644 >> > --- a/lldb/source/Commands/CommandObjectType.cpp >> > +++ b/lldb/source/Commands/CommandObjectType.cpp >> > @@ -11,6 +11,7 @@ >> > #include "lldb/Core/Debugger.h" >> > #include "lldb/Core/IOHandler.h" >> > #include "lldb/DataFormatters/DataVisualization.h" >> > +#include "lldb/DataFormatters/FormatClasses.h" >> > #include "lldb/Host/Config.h" >> > #include "lldb/Host/OptionParser.h" >> > #include "lldb/Interpreter/CommandInterpreter.h" >> > @@ -2302,7 +2303,13 @@ bool >> CommandObjectTypeSynthAdd::AddSynth(ConstString type_name, >> > // an actual type name. Matching a regex string against registered >> regexes >> > // doesn't work. >> > if (type == eRegularSynth) { >> > - if (category->AnyMatches(type_name, eFormatCategoryItemFilter, >> false)) { >> > + // It's not generally possible to get a type object here. For >> example, this >> > + // command can be run before loading any binaries. Do just a >> best-effort >> > + // name-based lookup here to try to prevent conflicts. >> > + FormattersMatchCandidate candidate_type(type_name, nullptr, >> TypeImpl(), >> > + >> FormattersMatchCandidate::Flags()); >> > + if (category->AnyMatches(candidate_type, eFormatCategoryItemFilter, >> > + false)) { >> > if (error) >> > error->SetErrorStringWithFormat("cannot add synthetic for type >> %s when " >> > "filter is defined in same >> category!", >> > @@ -2427,7 +2434,14 @@ class CommandObjectTypeFilterAdd : public >> CommandObjectParsed { >> > // if `type_name` is an actual type name. Matching a regex string >> against >> > // registered regexes doesn't work. >> > if (type == eRegularFilter) { >> > - if (category->AnyMatches(type_name, eFormatCategoryItemSynth, >> false)) { >> > + // It's not generally possible to get a type object here. For >> example, >> > + // this command can be run before loading any binaries. Do just a >> > + // best-effort name-based lookup here to try to prevent >> conflicts. >> > + FormattersMatchCandidate candidate_type( >> > + type_name, nullptr, TypeImpl(), >> FormattersMatchCandidate::Flags()); >> > + lldb::SyntheticChildrenSP entry; >> > + if (category->AnyMatches(candidate_type, >> eFormatCategoryItemSynth, >> > + false)) { >> > if (error) >> > error->SetErrorStringWithFormat("cannot add filter for type >> %s when " >> > "synthetic is defined in same >> " >> > >> > diff --git a/lldb/source/DataFormatters/DataVisualization.cpp >> b/lldb/source/DataFormatters/DataVisualization.cpp >> > index 53832492aa25..036c9372baf8 100644 >> > --- a/lldb/source/DataFormatters/DataVisualization.cpp >> > +++ b/lldb/source/DataFormatters/DataVisualization.cpp >> > @@ -66,10 +66,11 @@ >> DataVisualization::GetSyntheticForType(lldb::TypeNameSpecifierImplSP >> type_sp) { >> > } >> > >> > bool DataVisualization::AnyMatches( >> > - ConstString type_name, TypeCategoryImpl::FormatCategoryItems items, >> > - bool only_enabled, const char **matching_category, >> > + const FormattersMatchCandidate &candidate_type, >> > + TypeCategoryImpl::FormatCategoryItems items, bool only_enabled, >> > + const char **matching_category, >> > TypeCategoryImpl::FormatCategoryItems *matching_type) { >> > - return GetFormatManager().AnyMatches(type_name, items, only_enabled, >> > + return GetFormatManager().AnyMatches(candidate_type, items, >> only_enabled, >> > matching_category, >> matching_type); >> > } >> > >> > >> > diff --git a/lldb/source/DataFormatters/FormatManager.cpp >> b/lldb/source/DataFormatters/FormatManager.cpp >> > index db9f6057e842..166264df9933 100644 >> > --- a/lldb/source/DataFormatters/FormatManager.cpp >> > +++ b/lldb/source/DataFormatters/FormatManager.cpp >> > @@ -11,6 +11,7 @@ >> > #include "lldb/Core/Debugger.h" >> > #include "lldb/DataFormatters/FormattersHelpers.h" >> > #include "lldb/DataFormatters/LanguageCategory.h" >> > +#include "lldb/Interpreter/ScriptInterpreter.h" >> > #include "lldb/Target/ExecutionContext.h" >> > #include "lldb/Target/Language.h" >> > #include "lldb/Utility/LLDBLog.h" >> > @@ -178,19 +179,24 @@ void FormatManager::GetPossibleMatches( >> > FormattersMatchCandidate::Flags current_flags, bool root_level) { >> > compiler_type = compiler_type.GetTypeForFormatters(); >> > ConstString type_name(compiler_type.GetTypeName()); >> > + ScriptInterpreter *script_interpreter = >> > + valobj.GetTargetSP()->GetDebugger().GetScriptInterpreter(); >> > if (valobj.GetBitfieldBitSize() > 0) { >> > StreamString sstring; >> > sstring.Printf("%s:%d", type_name.AsCString(), >> valobj.GetBitfieldBitSize()); >> > ConstString bitfieldname(sstring.GetString()); >> > - entries.push_back({bitfieldname, current_flags}); >> > + entries.push_back({bitfieldname, script_interpreter, >> > + TypeImpl(compiler_type), current_flags}); >> > } >> > >> > if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) { >> > - entries.push_back({type_name, current_flags}); >> > + entries.push_back({type_name, script_interpreter, >> TypeImpl(compiler_type), >> > + current_flags}); >> > >> > ConstString display_type_name(compiler_type.GetTypeName()); >> > if (display_type_name != type_name) >> > - entries.push_back({display_type_name, current_flags}); >> > + entries.push_back({display_type_name, script_interpreter, >> > + TypeImpl(compiler_type), current_flags}); >> > } >> > >> > for (bool is_rvalue_ref = true, j = true; >> > @@ -245,9 +251,9 @@ void FormatManager::GetPossibleMatches( >> > for (lldb::LanguageType language_type : >> > GetCandidateLanguages(valobj.GetObjectRuntimeLanguage())) { >> > if (Language *language = Language::FindPlugin(language_type)) { >> > - for (ConstString candidate : >> > + for (const FormattersMatchCandidate& candidate : >> > language->GetPossibleFormattersMatches(valobj, use_dynamic)) >> { >> > - entries.push_back({candidate, current_flags}); >> > + entries.push_back(candidate); >> > } >> > } >> > } >> > >> > diff --git a/lldb/source/DataFormatters/TypeCategory.cpp >> b/lldb/source/DataFormatters/TypeCategory.cpp >> > index 1d5674968245..4d8663ea9c03 100644 >> > --- a/lldb/source/DataFormatters/TypeCategory.cpp >> > +++ b/lldb/source/DataFormatters/TypeCategory.cpp >> > @@ -184,20 +184,15 @@ uint32_t >> TypeCategoryImpl::GetCount(FormatCategoryItems items) { >> > return count; >> > } >> > >> > -bool TypeCategoryImpl::AnyMatches(ConstString type_name, >> > - FormatCategoryItems items, bool >> only_enabled, >> > - const char **matching_category, >> > - FormatCategoryItems *matching_type) { >> > +bool TypeCategoryImpl::AnyMatches( >> > + const FormattersMatchCandidate &candidate_type, >> 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; >> > - >> > if (items & eFormatCategoryItemFormat) { >> > - if (m_format_cont.AnyMatches(type_name)) { >> > + if (m_format_cont.AnyMatches(candidate_type)) { >> > if (matching_category) >> > *matching_category = m_name.GetCString(); >> > if (matching_type) >> > @@ -207,7 +202,7 @@ bool TypeCategoryImpl::AnyMatches(ConstString >> type_name, >> > } >> > >> > if (items & eFormatCategoryItemSummary) { >> > - if (m_summary_cont.AnyMatches(type_name)) { >> > + if (m_summary_cont.AnyMatches(candidate_type)) { >> > if (matching_category) >> > *matching_category = m_name.GetCString(); >> > if (matching_type) >> > @@ -217,7 +212,7 @@ bool TypeCategoryImpl::AnyMatches(ConstString >> type_name, >> > } >> > >> > if (items & eFormatCategoryItemFilter) { >> > - if (m_filter_cont.AnyMatches(type_name)) { >> > + if (m_filter_cont.AnyMatches(candidate_type)) { >> > if (matching_category) >> > *matching_category = m_name.GetCString(); >> > if (matching_type) >> > @@ -227,7 +222,7 @@ bool TypeCategoryImpl::AnyMatches(ConstString >> type_name, >> > } >> > >> > if (items & eFormatCategoryItemSynth) { >> > - if (m_synth_cont.AnyMatches(type_name)) { >> > + if (m_synth_cont.AnyMatches(candidate_type)) { >> > if (matching_category) >> > *matching_category = m_name.GetCString(); >> > if (matching_type) >> > >> > diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp >> b/lldb/source/DataFormatters/TypeCategoryMap.cpp >> > index aa8387b4deec..55635173cc8c 100644 >> > --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp >> > +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp >> > @@ -154,14 +154,15 @@ bool TypeCategoryMap::Get(uint32_t pos, ValueSP >> &entry) { >> > } >> > >> > bool TypeCategoryMap::AnyMatches( >> > - ConstString type_name, TypeCategoryImpl::FormatCategoryItems items, >> > - bool only_enabled, const char **matching_category, >> > + const FormattersMatchCandidate &candidate_type, >> > + TypeCategoryImpl::FormatCategoryItems items, bool only_enabled, >> > + const char **matching_category, >> > TypeCategoryImpl::FormatCategoryItems *matching_type) { >> > std::lock_guard<std::recursive_mutex> guard(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, >> > + if (pos->second->AnyMatches(candidate_type, items, only_enabled, >> > matching_category, matching_type)) >> > return true; >> > } >> > >> > diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp >> b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp >> > index 11d5b0813b58..9cbb40419167 100644 >> > --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp >> > +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp >> > @@ -12,6 +12,7 @@ >> > >> > #include "Plugins/ExpressionParser/Clang/ClangUtil.h" >> > #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" >> > +#include "lldb/Core/Debugger.h" >> > #include "lldb/Core/PluginManager.h" >> > #include "lldb/Core/ValueObject.h" >> > #include "lldb/DataFormatters/DataVisualization.h" >> > @@ -931,10 +932,10 @@ lldb::TypeCategoryImplSP >> ObjCLanguage::GetFormatters() { >> > return g_category; >> > } >> > >> > -std::vector<ConstString> >> > +std::vector<FormattersMatchCandidate> >> > ObjCLanguage::GetPossibleFormattersMatches(ValueObject &valobj, >> > lldb::DynamicValueType >> use_dynamic) { >> > - std::vector<ConstString> result; >> > + std::vector<FormattersMatchCandidate> result; >> > >> > if (use_dynamic == lldb::eNoDynamicValues) >> > return result; >> > @@ -959,7 +960,10 @@ >> ObjCLanguage::GetPossibleFormattersMatches(ValueObject &valobj, >> > if (!objc_class_sp) >> > break; >> > if (ConstString name = objc_class_sp->GetClassName()) >> > - result.push_back(name); >> > + result.push_back( >> > + {name, >> valobj.GetTargetSP()->GetDebugger().GetScriptInterpreter(), >> > + TypeImpl(objc_class_sp->GetType()), >> > + FormattersMatchCandidate::Flags{}}); >> > } while (false); >> > } >> > >> > >> > diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h >> b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h >> > index 914452086db7..b61348a3280e 100644 >> > --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h >> > +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h >> > @@ -108,7 +108,7 @@ class ObjCLanguage : public Language { >> > >> > lldb::TypeCategoryImplSP GetFormatters() override; >> > >> > - std::vector<ConstString> >> > + std::vector<FormattersMatchCandidate> >> > GetPossibleFormattersMatches(ValueObject &valobj, >> > lldb::DynamicValueType use_dynamic) >> override; >> > >> > >> > diff --git >> a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h >> b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h >> > index 4df235356737..7e18b0ef0804 100644 >> > --- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h >> > +++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h >> > @@ -75,6 +75,10 @@ bool LLDBSwigPythonWatchpointCallbackFunction( >> > const char *python_function_name, const char >> *session_dictionary_name, >> > const lldb::StackFrameSP &sb_frame, const lldb::WatchpointSP >> &sb_wp); >> > >> > +bool LLDBSwigPythonFormatterCallbackFunction( >> > + const char *python_function_name, const char >> *session_dictionary_name, >> > + lldb::TypeImplSP type_impl_sp); >> > + >> > bool LLDBSwigPythonCallTypeScript(const char *python_function_name, >> > const void *session_dictionary, >> > const lldb::ValueObjectSP &valobj_sp, >> > >> > diff --git >> a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp >> b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp >> > index d0f67a5684c5..37e3c94df870 100644 >> > --- >> a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp >> > +++ >> b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp >> > @@ -2154,6 +2154,14 @@ bool >> ScriptInterpreterPythonImpl::GetScriptedSummary( >> > return ret_val; >> > } >> > >> > +bool ScriptInterpreterPythonImpl::FormatterCallbackFunction( >> > + const char *python_function_name, TypeImplSP type_impl_sp) { >> > + Locker py_lock(this, >> > + Locker::AcquireLock | Locker::InitSession | >> Locker::NoSTDIN); >> > + return LLDBSwigPythonFormatterCallbackFunction( >> > + python_function_name, m_dictionary_name.c_str(), type_impl_sp); >> > +} >> > + >> > bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction( >> > void *baton, StoppointCallbackContext *context, user_id_t break_id, >> > user_id_t break_loc_id) { >> > >> > diff --git >> a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h >> b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h >> > index 3b80c67d201a..f4875bfb8d18 100644 >> > --- >> a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h >> > +++ >> b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h >> > @@ -202,6 +202,9 @@ class ScriptInterpreterPythonImpl : public >> ScriptInterpreterPython { >> > const TypeSummaryOptions &options, >> > std::string &retval) override; >> > >> > + bool FormatterCallbackFunction(const char *function_name, >> > + lldb::TypeImplSP type_impl_sp) >> override; >> > + >> > bool GetDocumentationForItem(const char *item, std::string &dest) >> override; >> > >> > bool GetShortHelpForCommandObject(StructuredData::GenericSP >> cmd_obj_sp, >> > >> > diff --git a/lldb/source/Target/Language.cpp >> b/lldb/source/Target/Language.cpp >> > index 6df36aeeb7b7..92431005cba9 100644 >> > --- a/lldb/source/Target/Language.cpp >> > +++ b/lldb/source/Target/Language.cpp >> > @@ -144,7 +144,7 @@ Language::GetHardcodedSynthetics() { >> > return {}; >> > } >> > >> > -std::vector<ConstString> >> > +std::vector<FormattersMatchCandidate> >> > Language::GetPossibleFormattersMatches(ValueObject &valobj, >> > lldb::DynamicValueType >> use_dynamic) { >> > return {}; >> > >> > diff --git >> a/lldb/test/API/functionalities/data-formatter/callback-matching/Makefile >> b/lldb/test/API/functionalities/data-formatter/callback-matching/Makefile >> > new file mode 100644 >> > index 000000000000..99998b20bcb0 >> > --- /dev/null >> > +++ >> b/lldb/test/API/functionalities/data-formatter/callback-matching/Makefile >> > @@ -0,0 +1,3 @@ >> > +CXX_SOURCES := main.cpp >> > + >> > +include Makefile.rules >> > >> > diff --git >> a/lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py >> b/lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py >> > new file mode 100644 >> > index 000000000000..91403d6d5f16 >> > --- /dev/null >> > +++ >> b/lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py >> > @@ -0,0 +1,49 @@ >> > +""" >> > +Test lldb data formatter callback-based matching. >> > +""" >> > + >> > +import lldb >> > +from lldbsuite.test.decorators import * >> > +from lldbsuite.test.lldbtest import * >> > +from lldbsuite.test import lldbutil >> > + >> > + >> > +class PythonSynthDataFormatterTestCase(TestBase): >> > + >> > + def setUp(self): >> > + # Call super's setUp(). >> > + TestBase.setUp(self) >> > + # Find the line number to break at. >> > + self.line = line_number('main.cpp', '// Set break point at >> this line.') >> > + >> > + def test_callback_matchers(self): >> > + """Test data formatter commands.""" >> > + self.build() >> > + >> > + _, process, thread, _ = lldbutil.run_to_line_breakpoint( >> > + self, lldb.SBFileSpec("main.cpp"), self.line) >> > + >> > + # Print derived without a formatter. >> > + self.expect("frame variable derived", >> > + substrs=['x = 2222', >> > + 'y = 3333']) >> > + >> > + # now set up a summary function that uses a python callback to >> match >> > + # classes that derive from `Base`. >> > + self.runCmd("command script import --allow-reload >> ./formatters_with_callback.py") >> > + >> > + # Now `derived` should use our callback summary + synthetic >> children. >> > + self.expect("frame variable derived", >> > + substrs=['hello from callback summary', >> > + 'synthetic_child = 9999']) >> > + >> > + # But not other classes. >> > + self.expect("frame variable base", matching=False, >> > + substrs=['hello from callback summary']) >> > + self.expect("frame variable base", >> > + substrs=['x = 1111']) >> > + >> > + self.expect("frame variable nd", matching=False, >> > + substrs=['hello from callback summary']) >> > + self.expect("frame variable nd", >> > + substrs=['z = 4444']) >> > >> > diff --git >> a/lldb/test/API/functionalities/data-formatter/callback-matching/formatters_with_callback.py >> b/lldb/test/API/functionalities/data-formatter/callback-matching/formatters_with_callback.py >> > new file mode 100644 >> > index 000000000000..60e919a94352 >> > --- /dev/null >> > +++ >> b/lldb/test/API/functionalities/data-formatter/callback-matching/formatters_with_callback.py >> > @@ -0,0 +1,39 @@ >> > +import lldb >> > + >> > +def derives_from_base(sbtype, internal_dict): >> > + for base in sbtype.get_bases_array(): >> > + if base.GetName() == "Base": >> > + return True >> > + return False >> > + >> > + >> > +class SynthProvider: >> > + def __init__(self, valobj, dict): >> > + self.valobj = valobj >> > + >> > + def num_children(self): >> > + return 1 >> > + >> > + def get_child_index(self, name): >> > + return 0 >> > + >> > + def get_child_at_index(self, index): >> > + if index == 0: >> > + return >> self.valobj.CreateValueFromExpression("synthetic_child", >> > + "9999") >> > + return None >> > + >> > + >> > +def __lldb_init_module(debugger, dict): >> > + cat = debugger.CreateCategory("callback_formatters") >> > + cat.AddTypeSummary( >> > + >> lldb.SBTypeNameSpecifier("formatters_with_callback.derives_from_base", >> > + lldb.eFormatterMatchCallback), >> > + lldb.SBTypeSummary.CreateWithScriptCode( >> > + "return 'hello from callback summary'")) >> > + cat.AddTypeSynthetic( >> > + >> lldb.SBTypeNameSpecifier('formatters_with_callback.derives_from_base', >> > + lldb.eFormatterMatchCallback), >> > + lldb.SBTypeSynthetic.CreateWithClassName( >> > + 'formatters_with_callback.SynthProvider')) >> > + cat.SetEnabled(True) >> > >> > diff --git >> a/lldb/test/API/functionalities/data-formatter/callback-matching/main.cpp >> b/lldb/test/API/functionalities/data-formatter/callback-matching/main.cpp >> > new file mode 100644 >> > index 000000000000..7732d87342a9 >> > --- /dev/null >> > +++ >> b/lldb/test/API/functionalities/data-formatter/callback-matching/main.cpp >> > @@ -0,0 +1,16 @@ >> > +struct Base { int x; }; >> > +struct Derived : public Base { int y; }; >> > + >> > +struct NonDerived { int z; }; >> > + >> > +int main() >> > +{ >> > + Base base = {1111}; >> > + >> > + Derived derived; >> > + derived.x = 2222; >> > + derived.y = 3333; >> > + >> > + NonDerived nd = {4444}; >> > + return 0; // Set break point at this line. >> > +} >> > >> > diff --git a/lldb/unittests/DataFormatter/FormattersContainerTest.cpp >> b/lldb/unittests/DataFormatter/FormattersContainerTest.cpp >> > index a28212391eae..41b01adfb9ec 100644 >> > --- a/lldb/unittests/DataFormatter/FormattersContainerTest.cpp >> > +++ b/lldb/unittests/DataFormatter/FormattersContainerTest.cpp >> > @@ -7,12 +7,20 @@ >> > >> //===----------------------------------------------------------------------===// >> > >> > #include "lldb/DataFormatters/FormattersContainer.h" >> > +#include "lldb/DataFormatters/FormatClasses.h" >> > >> > #include "gtest/gtest.h" >> > >> > using namespace lldb; >> > using namespace lldb_private; >> > >> > +// Creates a dummy candidate with just a type name in order to test >> the string >> > +// matching (exact name match and regex match) paths. >> > +FormattersMatchCandidate CandidateFromTypeName(const char *type_name) { >> > + return FormattersMatchCandidate(ConstString(type_name), nullptr, >> TypeImpl(), >> > + FormattersMatchCandidate::Flags()); >> > +} >> > + >> > // All the prefixes that the exact name matching will strip from the >> type. >> > static const std::vector<std::string> exact_name_prefixes = { >> > "", // no prefix. >> > @@ -25,63 +33,63 @@ TEST(TypeMatcherTests, ExactName) { >> > SCOPED_TRACE("Prefix: " + prefix); >> > >> > TypeMatcher matcher(ConstString(prefix + "Name")); >> > - EXPECT_TRUE(matcher.Matches(ConstString("class Name"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("struct Name"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("union Name"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("enum Name"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("Name"))); >> > - >> > - EXPECT_FALSE(matcher.Matches(ConstString("Name "))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("ame"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("Nam"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("am"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("a"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString(" "))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("class N"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("class "))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("class"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("class Name"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("struct Name"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("union Name"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("enum Name"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("Name"))); >> > + >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("Name "))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ame"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("Nam"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("am"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("a"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(" "))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class N"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class "))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class"))); >> > } >> > } >> > >> > // TypeMatcher that uses a regex to match a type name. >> > TEST(TypeMatcherTests, RegexName) { >> > TypeMatcher matcher(RegularExpression("^a[a-z]c$")); >> > - EXPECT_TRUE(matcher.Matches(ConstString("abc"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("azc"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("abc"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("azc"))); >> > >> > // FIXME: This isn't consistent with the 'exact' type name matches >> above. >> > - EXPECT_FALSE(matcher.Matches(ConstString("class abc"))); >> > - >> > - EXPECT_FALSE(matcher.Matches(ConstString("abbc"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString(" abc"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("abc "))); >> > - EXPECT_FALSE(matcher.Matches(ConstString(" abc "))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("XabcX"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("ac"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("aAc"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("ABC"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString(""))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class abc"))); >> > + >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("abbc"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(" abc"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("abc "))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(" abc "))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("XabcX"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ac"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("a[a-z]c"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("aAc"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ABC"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(""))); >> > } >> > >> > // TypeMatcher that only searches the type name. >> > TEST(TypeMatcherTests, RegexMatchPart) { >> > TypeMatcher matcher(RegularExpression("a[a-z]c")); >> > - EXPECT_TRUE(matcher.Matches(ConstString("class abc"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("abc"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString(" abc "))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("azc"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("abc "))); >> > - EXPECT_TRUE(matcher.Matches(ConstString(" abc "))); >> > - EXPECT_TRUE(matcher.Matches(ConstString(" abc"))); >> > - EXPECT_TRUE(matcher.Matches(ConstString("XabcX"))); >> > - >> > - EXPECT_FALSE(matcher.Matches(ConstString("abbc"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("ac"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("aAc"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString("ABC"))); >> > - EXPECT_FALSE(matcher.Matches(ConstString(""))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("class abc"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("abc"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName(" abc "))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("azc"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("abc "))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName(" abc "))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName(" abc"))); >> > + EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("XabcX"))); >> > + >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("abbc"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ac"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("a[a-z]c"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("aAc"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ABC"))); >> > + EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(""))); >> > } >> > >> > // GetMatchString for exact type name matchers. >> > >> > diff --git >> a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp >> b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp >> > index 6ac4606b5a84..87e4a03ee77b 100644 >> > --- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp >> > +++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp >> > @@ -67,6 +67,12 @@ bool >> lldb_private::LLDBSwigPythonWatchpointCallbackFunction( >> > return false; >> > } >> > >> > +bool lldb_private::LLDBSwigPythonFormatterCallbackFunction( >> > + const char *python_function_name, const char >> *session_dictionary_name, >> > + lldb::TypeImplSP type_impl_sp) { >> > + return false; >> > +} >> > + >> > bool lldb_private::LLDBSwigPythonCallTypeScript( >> > const char *python_function_name, const void *session_dictionary, >> > const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper, >> > >> > >> > >> > _______________________________________________ >> > lldb-commits mailing list >> > lldb-commits@lists.llvm.org >> > https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits >> >>
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits