[Lldb-commits] [lldb] d765664 - [lldb] Add matching based on Python callbacks for data formatters.

Jim Ingham via lldb-commits lldb-commits at lists.llvm.org
Wed Oct 19 14:00:28 PDT 2022


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 at 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 at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits



More information about the lldb-commits mailing list