<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">That's actually a better idea. Relanded it with the member removed and constructor deleted. Thanks!<div class=""><br class=""></div><div class="">- Raphael<br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On 23 Jul 2020, at 09:49, Eric Christopher <<a href="mailto:echristo@gmail.com" class="">echristo@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Hi Raphael,<div class=""><br class=""></div><div class="">I've temporarily reverted this again with hopefully a better explanation here:</div><div class=""><br class=""></div><div class="">echristo@athyra ~/s/llvm-project> git push<br class="">To <a href="http://github.com" class="">github.com</a>:llvm/llvm-project.git<br class="">   55c0f12a869..3a75466f41b  master -> master<br class=""></div><div class=""><br class=""></div><div class="">One review thought: If you don't want people using the default constructor for TypeMatcher perhaps just delete it? (i.e. = delete). If that's not where you were going then perhaps we can come up with another way around this :)</div><div class=""><br class=""></div><div class="">Thanks and sorry for the inconvenience!</div><div class=""><br class=""></div><div class="">-eric</div></div><br class=""><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Jul 22, 2020 at 12:34 AM Raphael Isemann via lldb-commits <<a href="mailto:lldb-commits@lists.llvm.org" class="">lldb-commits@lists.llvm.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br class="">
Author: Raphael Isemann<br class="">
Date: 2020-07-22T09:32:28+02:00<br class="">
New Revision: 074b121642b286afb16adeebda5ec8236f7b8ea9<br class="">
<br class="">
URL: <a href="https://github.com/llvm/llvm-project/commit/074b121642b286afb16adeebda5ec8236f7b8ea9" rel="noreferrer" target="_blank" class="">https://github.com/llvm/llvm-project/commit/074b121642b286afb16adeebda5ec8236f7b8ea9</a><br class="">
DIFF: <a href="https://github.com/llvm/llvm-project/commit/074b121642b286afb16adeebda5ec8236f7b8ea9.diff" rel="noreferrer" target="_blank" class="">https://github.com/llvm/llvm-project/commit/074b121642b286afb16adeebda5ec8236f7b8ea9.diff</a><br class="">
<br class="">
LOG: Reland [lldb] Unify type name matching in FormattersContainer<br class="">
<br class="">
This was originally reverted because the Linux bots were red after this landed,<br class="">
but it seems that was actually caused by a different commit. I double checked<br class="">
that this works on Linux, so let's reland this on Linux.<br class="">
<br class="">
Summary:<br class="">
<br class="">
FormattersContainer stores LLDB's formatters. It's implemented as a templated<br class="">
map-like data structures that supports any kind of value type and only allows<br class="">
ConstString and RegularExpression as the key types. The keys are used for<br class="">
matching type names (e.g., the ConstString key `std::vector` matches the type<br class="">
with the same name while RegularExpression keys match any type where the<br class="">
RegularExpression instance matches).<br class="">
<br class="">
The fact that a single FormattersContainer can only match either by string<br class="">
comparison or regex matching (depending on the KeyType) causes us to always have<br class="">
two FormatterContainer instances in all the formatting code. This also leads to<br class="">
us having every type name matching logic in LLDB twice. For example,<br class="">
TypeCategory has to implement every method twice (one string matching one, one<br class="">
regex matching one).<br class="">
<br class="">
This patch changes FormattersContainer to instead have a single `TypeMatcher`<br class="">
key that wraps the logic for string-based and regex-based type matching and is<br class="">
now the only possible KeyType for the FormattersContainer. This means that a<br class="">
single FormattersContainer can now match types with both regex and string<br class="">
comparison.<br class="">
<br class="">
To summarize the changes in this patch:<br class="">
* Remove all the `*_Impl` methods from `FormattersContainer`<br class="">
* Instead call the FormatMap functions from `FormattersContainer` with a<br class="">
  `TypeMatcher` type that does the respective matching.<br class="">
* Replace `ConstString` with `TypeMatcher` in the few places that directly<br class="">
  interact with `FormattersContainer`.<br class="">
<br class="">
I'm working on some follow up patches that I split up because they deserve their<br class="">
own review:<br class="">
<br class="">
* Unify FormatMap and FormattersContainer (they are nearly identical now).<br class="">
* Delete the duplicated half of all the type matching code that can now use one<br class="">
  interface.<br class="">
* Propagate TypeMatcher through all the formatter code interfaces instead of<br class="">
  always offering two functions for everything.<br class="">
<br class="">
There is one ugly design part that I couldn't get rid of yet and that is that we<br class="">
have to support getting back the string used to construct a `TypeMatcher` later<br class="">
on. The reason for this is that LLDB only supports referencing existing type<br class="">
matchers by just typing their respective input string again (without even<br class="">
supplying if it's a regex or not).<br class="">
<br class="">
Reviewers: davide, mib<br class="">
<br class="">
Reviewed By: mib<br class="">
<br class="">
Subscribers: mgorny, JDevlieghere<br class="">
<br class="">
Differential Revision: <a href="https://reviews.llvm.org/D84151" rel="noreferrer" target="_blank" class="">https://reviews.llvm.org/D84151</a><br class="">
<br class="">
Added: <br class="">
    lldb/unittests/DataFormatter/FormattersContainerTest.cpp<br class="">
<br class="">
Modified: <br class="">
    lldb/include/lldb/DataFormatters/DataVisualization.h<br class="">
    lldb/include/lldb/DataFormatters/FormatManager.h<br class="">
    lldb/include/lldb/DataFormatters/FormattersContainer.h<br class="">
    lldb/include/lldb/DataFormatters/TypeCategory.h<br class="">
    lldb/include/lldb/DataFormatters/TypeCategoryMap.h<br class="">
    lldb/source/Commands/CommandObjectType.cpp<br class="">
    lldb/source/DataFormatters/DataVisualization.cpp<br class="">
    lldb/source/DataFormatters/FormatManager.cpp<br class="">
    lldb/unittests/DataFormatter/CMakeLists.txt<br class="">
<br class="">
Removed: <br class="">
<br class="">
<br class="">
<br class="">
################################################################################<br class="">
diff  --git a/lldb/include/lldb/DataFormatters/DataVisualization.h b/lldb/include/lldb/DataFormatters/DataVisualization.h<br class="">
index b053aa074d9e..7be07d65acdd 100644<br class="">
--- a/lldb/include/lldb/DataFormatters/DataVisualization.h<br class="">
+++ b/lldb/include/lldb/DataFormatters/DataVisualization.h<br class="">
@@ -69,9 +69,9 @@ class DataVisualization {<br class="">
<br class="">
     static void Clear();<br class="">
<br class="">
-    static void<br class="">
-    ForEach(std::function<bool(ConstString, const lldb::TypeSummaryImplSP &)><br class="">
-                callback);<br class="">
+    static void ForEach(std::function<bool(const TypeMatcher &,<br class="">
+                                           const lldb::TypeSummaryImplSP &)><br class="">
+                            callback);<br class="">
<br class="">
     static uint32_t GetCount();<br class="">
   };<br class="">
<br class="">
diff  --git a/lldb/include/lldb/DataFormatters/FormatManager.h b/lldb/include/lldb/DataFormatters/FormatManager.h<br class="">
index 56a0303f9b02..98c5b132c203 100644<br class="">
--- a/lldb/include/lldb/DataFormatters/FormatManager.h<br class="">
+++ b/lldb/include/lldb/DataFormatters/FormatManager.h<br class="">
@@ -34,7 +34,7 @@ namespace lldb_private {<br class="">
 // this file's objects directly<br class="">
<br class="">
 class FormatManager : public IFormatChangeListener {<br class="">
-  typedef FormatMap<ConstString, TypeSummaryImpl> NamedSummariesMap;<br class="">
+  typedef FormatMap<TypeSummaryImpl> NamedSummariesMap;<br class="">
   typedef TypeCategoryMap::MapType::iterator CategoryMapIterator;<br class="">
<br class="">
 public:<br class="">
@@ -144,13 +144,6 @@ class FormatManager : public IFormatChangeListener {<br class="">
<br class="">
   static const char *GetFormatAsCString(lldb::Format format);<br class="">
<br class="">
-  // if the user tries to add formatters for, say, "struct Foo" those will not<br class="">
-  // match any type because of the way we strip qualifiers from typenames this<br class="">
-  // method looks for the case where the user is adding a<br class="">
-  // "class","struct","enum" or "union" Foo and strips the unnecessary<br class="">
-  // qualifier<br class="">
-  static ConstString GetValidTypeName(ConstString type);<br class="">
-<br class="">
   // when DataExtractor dumps a vectorOfT, it uses a predefined format for each<br class="">
   // item this method returns it, or eFormatInvalid if vector_format is not a<br class="">
   // vectorOf<br class="">
<br class="">
diff  --git a/lldb/include/lldb/DataFormatters/FormattersContainer.h b/lldb/include/lldb/DataFormatters/FormattersContainer.h<br class="">
index a22cf494bf8a..69dd1ecf1752 100644<br class="">
--- a/lldb/include/lldb/DataFormatters/FormattersContainer.h<br class="">
+++ b/lldb/include/lldb/DataFormatters/FormattersContainer.h<br class="">
@@ -37,57 +37,113 @@ class IFormatChangeListener {<br class="">
   virtual uint32_t GetCurrentRevision() = 0;<br class="">
 };<br class="">
<br class="">
-// if the user tries to add formatters for, say, "struct Foo" those will not<br class="">
-// match any type because of the way we strip qualifiers from typenames this<br class="">
-// method looks for the case where the user is adding a "class","struct","enum"<br class="">
-// or "union" Foo and strips the unnecessary qualifier<br class="">
-static inline ConstString GetValidTypeName_Impl(ConstString type) {<br class="">
-  if (type.IsEmpty())<br class="">
-    return type;<br class="">
+/// Class for matching type names.<br class="">
+class TypeMatcher {<br class="">
+  RegularExpression m_type_name_regex;<br class="">
+  ConstString m_type_name;<br class="">
+  /// False if m_type_name_regex should be used for matching. False if this is<br class="">
+  /// just matching by comparing with m_type_name string.<br class="">
+  bool m_is_regex;<br class="">
+  /// True iff this TypeMatcher is invalid and shouldn't be used for any<br class="">
+  /// type matching logic.<br class="">
+  bool m_valid = true;<br class="">
+<br class="">
+  // if the user tries to add formatters for, say, "struct Foo" those will not<br class="">
+  // match any type because of the way we strip qualifiers from typenames this<br class="">
+  // method looks for the case where the user is adding a<br class="">
+  // "class","struct","enum" or "union" Foo and strips the unnecessary qualifier<br class="">
+  static ConstString StripTypeName(ConstString type) {<br class="">
+    if (type.IsEmpty())<br class="">
+      return type;<br class="">
+<br class="">
+    std::string type_cstr(type.AsCString());<br class="">
+    StringLexer type_lexer(type_cstr);<br class="">
+<br class="">
+    type_lexer.AdvanceIf("class ");<br class="">
+    type_lexer.AdvanceIf("enum ");<br class="">
+    type_lexer.AdvanceIf("struct ");<br class="">
+    type_lexer.AdvanceIf("union ");<br class="">
+<br class="">
+    while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)<br class="">
+      ;<br class="">
+<br class="">
+    return ConstString(type_lexer.GetUnlexed());<br class="">
+  }<br class="">
<br class="">
-  std::string type_cstr(type.AsCString());<br class="">
-  StringLexer type_lexer(type_cstr);<br class="">
+public:<br class="">
+  /// Creates an invalid matcher that should not be used for any type matching.<br class="">
+  TypeMatcher() : m_valid(false) {}<br class="">
+  /// Creates a matcher that accepts any type with exactly the given type name.<br class="">
+  TypeMatcher(ConstString type_name)<br class="">
+      : m_type_name(type_name), m_is_regex(false) {}<br class="">
+  /// Creates a matcher that accepts any type matching the given regex.<br class="">
+  TypeMatcher(RegularExpression regex)<br class="">
+      : m_type_name_regex(regex), m_is_regex(true) {}<br class="">
+<br class="">
+  /// True iff this matches the given type name.<br class="">
+  bool Matches(ConstString type_name) const {<br class="">
+    assert(m_valid && "Using invalid TypeMatcher");<br class="">
+<br class="">
+    if (m_is_regex)<br class="">
+      return m_type_name_regex.Execute(type_name.GetStringRef());<br class="">
+    return m_type_name == type_name ||<br class="">
+           StripTypeName(m_type_name) == StripTypeName(type_name);<br class="">
+  }<br class="">
<br class="">
-  type_lexer.AdvanceIf("class ");<br class="">
-  type_lexer.AdvanceIf("enum ");<br class="">
-  type_lexer.AdvanceIf("struct ");<br class="">
-  type_lexer.AdvanceIf("union ");<br class="">
+  /// Returns the underlying match string for this TypeMatcher.<br class="">
+  ConstString GetMatchString() const {<br class="">
+    assert(m_valid && "Using invalid TypeMatcher");<br class="">
<br class="">
-  while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)<br class="">
-    ;<br class="">
+    if (m_is_regex)<br class="">
+      return ConstString(m_type_name_regex.GetText());<br class="">
+    return StripTypeName(m_type_name);<br class="">
+  }<br class="">
<br class="">
-  return ConstString(type_lexer.GetUnlexed());<br class="">
-}<br class="">
+  /// Returns true if this TypeMatcher and the given one were most created by<br class="">
+  /// the same match string.<br class="">
+  /// The main purpose of this function is to find existing TypeMatcher<br class="">
+  /// instances by the user input that created them. This is necessary as LLDB<br class="">
+  /// allows referencing existing TypeMatchers in commands by the user input<br class="">
+  /// that originally created them:<br class="">
+  /// (lldb) type summary add --summary-string \"A\" -x TypeName<br class="">
+  /// (lldb) type summary delete TypeName<br class="">
+  bool CreatedBySameMatchString(TypeMatcher other) const {<br class="">
+    assert(m_valid && "Using invalid TypeMatcher");<br class="">
+<br class="">
+    return GetMatchString() == other.GetMatchString();<br class="">
+  }<br class="">
+};<br class="">
<br class="">
-template <typename KeyType, typename ValueType> class FormattersContainer;<br class="">
+template <typename ValueType> class FormattersContainer;<br class="">
<br class="">
-template <typename KeyType, typename ValueType> class FormatMap {<br class="">
+template <typename ValueType> class FormatMap {<br class="">
 public:<br class="">
   typedef typename ValueType::SharedPointer ValueSP;<br class="">
-  typedef std::vector<std::pair<KeyType, ValueSP>> MapType;<br class="">
+  typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType;<br class="">
   typedef typename MapType::iterator MapIterator;<br class="">
-  typedef std::function<bool(const KeyType &, const ValueSP &)> ForEachCallback;<br class="">
+  typedef std::function<bool(const TypeMatcher &, const ValueSP &)><br class="">
+      ForEachCallback;<br class="">
<br class="">
   FormatMap(IFormatChangeListener *lst)<br class="">
       : m_map(), m_map_mutex(), listener(lst) {}<br class="">
<br class="">
-  void Add(KeyType name, const ValueSP &entry) {<br class="">
+  void Add(TypeMatcher matcher, const ValueSP &entry) {<br class="">
     if (listener)<br class="">
       entry->GetRevision() = listener->GetCurrentRevision();<br class="">
     else<br class="">
       entry->GetRevision() = 0;<br class="">
<br class="">
     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);<br class="">
-    Delete(name);<br class="">
-    m_map.emplace_back(std::move(name), std::move(entry));<br class="">
+    Delete(matcher);<br class="">
+    m_map.emplace_back(std::move(matcher), std::move(entry));<br class="">
     if (listener)<br class="">
       listener->Changed();<br class="">
   }<br class="">
<br class="">
-  bool Delete(const KeyType &name) {<br class="">
+  bool Delete(const TypeMatcher &matcher) {<br class="">
     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);<br class="">
     for (MapIterator iter = m_map.begin(); iter != m_map.end(); ++iter)<br class="">
-      if (iter->first == name) {<br class="">
+      if (iter->first.CreatedBySameMatchString(matcher)) {<br class="">
         m_map.erase(iter);<br class="">
         if (listener)<br class="">
           listener->Changed();<br class="">
@@ -103,10 +159,10 @@ template <typename KeyType, typename ValueType> class FormatMap {<br class="">
       listener->Changed();<br class="">
   }<br class="">
<br class="">
-  bool Get(const KeyType &name, ValueSP &entry) {<br class="">
+  bool Get(const TypeMatcher &matcher, ValueSP &entry) {<br class="">
     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);<br class="">
     for (const auto &pos : m_map)<br class="">
-      if (pos.first == name) {<br class="">
+      if (pos.first.CreatedBySameMatchString(matcher)) {<br class="">
         entry = pos.second;<br class="">
         return true;<br class="">
       }<br class="">
@@ -117,7 +173,7 @@ template <typename KeyType, typename ValueType> class FormatMap {<br class="">
     if (callback) {<br class="">
       std::lock_guard<std::recursive_mutex> guard(m_map_mutex);<br class="">
       for (const auto &pos : m_map) {<br class="">
-        const KeyType &type = pos.first;<br class="">
+        const TypeMatcher &type = pos.first;<br class="">
         if (!callback(type, pos.second))<br class="">
           break;<br class="">
       }<br class="">
@@ -134,10 +190,10 @@ template <typename KeyType, typename ValueType> class FormatMap {<br class="">
   }<br class="">
<br class="">
   // If caller holds the mutex we could return a reference without copy ctor.<br class="">
-  KeyType GetKeyAtIndex(size_t index) {<br class="">
+  llvm::Optional<TypeMatcher> GetKeyAtIndex(size_t index) {<br class="">
     std::lock_guard<std::recursive_mutex> guard(m_map_mutex);<br class="">
     if (index >= m_map.size())<br class="">
-      return {};<br class="">
+      return llvm::None;<br class="">
     return m_map[index].first;<br class="">
   }<br class="">
<br class="">
@@ -150,41 +206,43 @@ template <typename KeyType, typename ValueType> class FormatMap {<br class="">
<br class="">
   std::recursive_mutex &mutex() { return m_map_mutex; }<br class="">
<br class="">
-  friend class FormattersContainer<KeyType, ValueType>;<br class="">
+  friend class FormattersContainer<ValueType>;<br class="">
   friend class FormatManager;<br class="">
 };<br class="">
<br class="">
-template <typename KeyType, typename ValueType> class FormattersContainer {<br class="">
+template <typename ValueType> class FormattersContainer {<br class="">
 protected:<br class="">
-  typedef FormatMap<KeyType, ValueType> BackEndType;<br class="">
+  typedef FormatMap<ValueType> BackEndType;<br class="">
<br class="">
 public:<br class="">
-  typedef typename BackEndType::MapType MapType;<br class="">
-  typedef typename MapType::iterator MapIterator;<br class="">
-  typedef KeyType MapKeyType;<br class="">
   typedef std::shared_ptr<ValueType> MapValueType;<br class="">
   typedef typename BackEndType::ForEachCallback ForEachCallback;<br class="">
-  typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>><br class="">
+  typedef typename std::shared_ptr<FormattersContainer<ValueType>><br class="">
       SharedPointer;<br class="">
<br class="">
   friend class TypeCategoryImpl;<br class="">
<br class="">
   FormattersContainer(IFormatChangeListener *lst) : m_format_map(lst) {}<br class="">
<br class="">
-  void Add(MapKeyType type, const MapValueType &entry) {<br class="">
-    Add_Impl(std::move(type), entry, static_cast<KeyType *>(nullptr));<br class="">
+  void Add(TypeMatcher type, const MapValueType &entry) {<br class="">
+    m_format_map.Add(std::move(type), entry);<br class="">
   }<br class="">
<br class="">
-  bool Delete(ConstString type) {<br class="">
-    return Delete_Impl(type, static_cast<KeyType *>(nullptr));<br class="">
-  }<br class="">
+  bool Delete(TypeMatcher type) { return m_format_map.Delete(type); }<br class="">
<br class="">
   bool Get(ConstString type, MapValueType &entry) {<br class="">
-    return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));<br class="">
+    std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());<br class="">
+    for (auto &formatter : llvm::reverse(m_format_map.map())) {<br class="">
+      if (formatter.first.Matches(type)) {<br class="">
+        entry = formatter.second;<br class="">
+        return true;<br class="">
+      }<br class="">
+    }<br class="">
+    return false;<br class="">
   }<br class="">
<br class="">
   bool GetExact(ConstString type, MapValueType &entry) {<br class="">
-    return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));<br class="">
+    return m_format_map.Get(type, entry);<br class="">
   }<br class="">
<br class="">
   MapValueType GetAtIndex(size_t index) {<br class="">
@@ -192,8 +250,12 @@ template <typename KeyType, typename ValueType> class FormattersContainer {<br class="">
   }<br class="">
<br class="">
   lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {<br class="">
-    return GetTypeNameSpecifierAtIndex_Impl(index,<br class="">
-                                            static_cast<KeyType *>(nullptr));<br class="">
+    llvm::Optional<TypeMatcher> type_matcher =<br class="">
+        m_format_map.GetKeyAtIndex(index);<br class="">
+    if (!type_matcher)<br class="">
+      return lldb::TypeNameSpecifierImplSP();<br class="">
+    return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(<br class="">
+        type_matcher->GetMatchString().GetStringRef(), true));<br class="">
   }<br class="">
<br class="">
   void Clear() { m_format_map.Clear(); }<br class="">
@@ -208,91 +270,6 @@ template <typename KeyType, typename ValueType> class FormattersContainer {<br class="">
   FormattersContainer(const FormattersContainer &) = delete;<br class="">
   const FormattersContainer &operator=(const FormattersContainer &) = delete;<br class="">
<br class="">
-  void Add_Impl(MapKeyType type, const MapValueType &entry,<br class="">
-                RegularExpression *dummy) {<br class="">
-    m_format_map.Add(std::move(type), entry);<br class="">
-  }<br class="">
-<br class="">
-  void Add_Impl(ConstString type, const MapValueType &entry,<br class="">
-                ConstString *dummy) {<br class="">
-    m_format_map.Add(GetValidTypeName_Impl(type), entry);<br class="">
-  }<br class="">
-<br class="">
-  bool Delete_Impl(ConstString type, ConstString *dummy) {<br class="">
-    return m_format_map.Delete(type);<br class="">
-  }<br class="">
-<br class="">
-  bool Delete_Impl(ConstString type, RegularExpression *dummy) {<br class="">
-    std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());<br class="">
-    MapIterator pos, end = m_format_map.map().end();<br class="">
-    for (pos = m_format_map.map().begin(); pos != end; pos++) {<br class="">
-      const RegularExpression &regex = pos->first;<br class="">
-      if (type.GetStringRef() == regex.GetText()) {<br class="">
-        m_format_map.map().erase(pos);<br class="">
-        if (m_format_map.listener)<br class="">
-          m_format_map.listener->Changed();<br class="">
-        return true;<br class="">
-      }<br class="">
-    }<br class="">
-    return false;<br class="">
-  }<br class="">
-<br class="">
-  bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {<br class="">
-    return m_format_map.Get(type, entry);<br class="">
-  }<br class="">
-<br class="">
-  bool GetExact_Impl(ConstString type, MapValueType &entry,<br class="">
-                     ConstString *dummy) {<br class="">
-    return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));<br class="">
-  }<br class="">
-<br class="">
-  lldb::TypeNameSpecifierImplSP<br class="">
-  GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) {<br class="">
-    ConstString key = m_format_map.GetKeyAtIndex(index);<br class="">
-    if (key)<br class="">
-      return lldb::TypeNameSpecifierImplSP(<br class="">
-          new TypeNameSpecifierImpl(key.GetStringRef(), false));<br class="">
-    else<br class="">
-      return lldb::TypeNameSpecifierImplSP();<br class="">
-  }<br class="">
-<br class="">
-  lldb::TypeNameSpecifierImplSP<br class="">
-  GetTypeNameSpecifierAtIndex_Impl(size_t index, RegularExpression *dummy) {<br class="">
-    RegularExpression regex = m_format_map.GetKeyAtIndex(index);<br class="">
-    if (regex == RegularExpression())<br class="">
-      return lldb::TypeNameSpecifierImplSP();<br class="">
-    return lldb::TypeNameSpecifierImplSP(<br class="">
-        new TypeNameSpecifierImpl(regex.GetText().str().c_str(), true));<br class="">
-  }<br class="">
-<br class="">
-  bool Get_Impl(ConstString key, MapValueType &value,<br class="">
-                RegularExpression *dummy) {<br class="">
-    llvm::StringRef key_str = key.GetStringRef();<br class="">
-    std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());<br class="">
-    // Patterns are matched in reverse-chronological order.<br class="">
-    for (const auto &pos : llvm::reverse(m_format_map.map())) {<br class="">
-      const RegularExpression &regex = pos.first;<br class="">
-      if (regex.Execute(key_str)) {<br class="">
-        value = pos.second;<br class="">
-        return true;<br class="">
-      }<br class="">
-    }<br class="">
-    return false;<br class="">
-  }<br class="">
-<br class="">
-  bool GetExact_Impl(ConstString key, MapValueType &value,<br class="">
-                     RegularExpression *dummy) {<br class="">
-    std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());<br class="">
-    for (const auto &pos : m_format_map.map()) {<br class="">
-      const RegularExpression &regex = pos.first;<br class="">
-      if (regex.GetText() == key.GetStringRef()) {<br class="">
-        value = pos.second;<br class="">
-        return true;<br class="">
-      }<br class="">
-    }<br class="">
-    return false;<br class="">
-  }<br class="">
-<br class="">
   bool Get(const FormattersMatchVector &candidates, MapValueType &entry) {<br class="">
     for (const FormattersMatchCandidate &candidate : candidates) {<br class="">
       if (Get(candidate.GetTypeName(), entry)) {<br class="">
<br class="">
diff  --git a/lldb/include/lldb/DataFormatters/TypeCategory.h b/lldb/include/lldb/DataFormatters/TypeCategory.h<br class="">
index 11614fc67cd2..4c8a7e14be12 100644<br class="">
--- a/lldb/include/lldb/DataFormatters/TypeCategory.h<br class="">
+++ b/lldb/include/lldb/DataFormatters/TypeCategory.h<br class="">
@@ -25,12 +25,11 @@ namespace lldb_private {<br class="">
<br class="">
 template <typename FormatterImpl> class FormatterContainerPair {<br class="">
 public:<br class="">
-  typedef FormattersContainer<ConstString, FormatterImpl> ExactMatchContainer;<br class="">
-  typedef FormattersContainer<RegularExpression, FormatterImpl><br class="">
-      RegexMatchContainer;<br class="">
+  typedef FormattersContainer<FormatterImpl> ExactMatchContainer;<br class="">
+  typedef FormattersContainer<FormatterImpl> RegexMatchContainer;<br class="">
<br class="">
-  typedef typename ExactMatchContainer::MapType ExactMatchMap;<br class="">
-  typedef typename RegexMatchContainer::MapType RegexMatchMap;<br class="">
+  typedef TypeMatcher ExactMatchMap;<br class="">
+  typedef TypeMatcher RegexMatchMap;<br class="">
<br class="">
   typedef typename ExactMatchContainer::MapValueType MapValueType;<br class="">
<br class="">
@@ -348,19 +347,13 @@ class TypeCategoryImpl {<br class="">
   friend class LanguageCategory;<br class="">
   friend class TypeCategoryMap;<br class="">
<br class="">
-  friend class FormattersContainer<ConstString, TypeFormatImpl>;<br class="">
-  friend class FormattersContainer<lldb::RegularExpressionSP, TypeFormatImpl>;<br class="">
+  friend class FormattersContainer<TypeFormatImpl>;<br class="">
<br class="">
-  friend class FormattersContainer<ConstString, TypeSummaryImpl>;<br class="">
-  friend class FormattersContainer<lldb::RegularExpressionSP, TypeSummaryImpl>;<br class="">
+  friend class FormattersContainer<TypeSummaryImpl>;<br class="">
<br class="">
-  friend class FormattersContainer<ConstString, TypeFilterImpl>;<br class="">
-  friend class FormattersContainer<lldb::RegularExpressionSP, TypeFilterImpl>;<br class="">
-<br class="">
-  friend class FormattersContainer<ConstString, ScriptedSyntheticChildren>;<br class="">
-  friend class FormattersContainer<lldb::RegularExpressionSP,<br class="">
-                                   ScriptedSyntheticChildren>;<br class="">
+  friend class FormattersContainer<TypeFilterImpl>;<br class="">
<br class="">
+  friend class FormattersContainer<ScriptedSyntheticChildren>;<br class="">
 };<br class="">
<br class="">
 } // namespace lldb_private<br class="">
<br class="">
diff  --git a/lldb/include/lldb/DataFormatters/TypeCategoryMap.h b/lldb/include/lldb/DataFormatters/TypeCategoryMap.h<br class="">
index 832652f7d745..6cd773786386 100644<br class="">
--- a/lldb/include/lldb/DataFormatters/TypeCategoryMap.h<br class="">
+++ b/lldb/include/lldb/DataFormatters/TypeCategoryMap.h<br class="">
@@ -103,7 +103,7 @@ class TypeCategoryMap {<br class="">
<br class="">
   std::recursive_mutex &mutex() { return m_map_mutex; }<br class="">
<br class="">
-  friend class FormattersContainer<KeyType, ValueType>;<br class="">
+  friend class FormattersContainer<ValueType>;<br class="">
   friend class FormatManager;<br class="">
 };<br class="">
 } // namespace lldb_private<br class="">
<br class="">
diff  --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp<br class="">
index b2020f26621f..b23f91de0ce6 100644<br class="">
--- a/lldb/source/Commands/CommandObjectType.cpp<br class="">
+++ b/lldb/source/Commands/CommandObjectType.cpp<br class="">
@@ -1066,13 +1066,15 @@ class CommandObjectTypeFormatterList : public CommandObjectParsed {<br class="">
       TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach;<br class="">
       foreach<br class="">
         .SetExact([&result, &formatter_regex, &any_printed](<br class="">
-                      ConstString name,<br class="">
+                      const TypeMatcher &type_matcher,<br class="">
                       const FormatterSharedPointer &format_sp) -> bool {<br class="">
           if (formatter_regex) {<br class="">
             bool escape = true;<br class="">
-            if (name.GetStringRef() == formatter_regex->GetText()) {<br class="">
+            if (type_matcher.CreatedBySameMatchString(<br class="">
+                    ConstString(formatter_regex->GetText()))) {<br class="">
               escape = false;<br class="">
-            } else if (formatter_regex->Execute(name.GetStringRef())) {<br class="">
+            } else if (formatter_regex->Execute(<br class="">
+                           type_matcher.GetMatchString().GetStringRef())) {<br class="">
               escape = false;<br class="">
             }<br class="">
<br class="">
@@ -1081,20 +1083,23 @@ class CommandObjectTypeFormatterList : public CommandObjectParsed {<br class="">
           }<br class="">
<br class="">
           any_printed = true;<br class="">
-          result.GetOutputStream().Printf("%s: %s\n", name.AsCString(),<br class="">
-                                          format_sp->GetDescription().c_str());<br class="">
+          result.GetOutputStream().Printf(<br class="">
+              "%s: %s\n", type_matcher.GetMatchString().GetCString(),<br class="">
+              format_sp->GetDescription().c_str());<br class="">
           return true;<br class="">
         });<br class="">
<br class="">
       foreach<br class="">
         .SetWithRegex([&result, &formatter_regex, &any_printed](<br class="">
-                          const RegularExpression &regex,<br class="">
+                          const TypeMatcher &type_matcher,<br class="">
                           const FormatterSharedPointer &format_sp) -> bool {<br class="">
           if (formatter_regex) {<br class="">
             bool escape = true;<br class="">
-            if (regex.GetText() == formatter_regex->GetText()) {<br class="">
+            if (type_matcher.CreatedBySameMatchString(<br class="">
+                    ConstString(formatter_regex->GetText()))) {<br class="">
               escape = false;<br class="">
-            } else if (formatter_regex->Execute(regex.GetText())) {<br class="">
+            } else if (formatter_regex->Execute(<br class="">
+                           type_matcher.GetMatchString().GetStringRef())) {<br class="">
               escape = false;<br class="">
             }<br class="">
<br class="">
@@ -1103,9 +1108,9 @@ class CommandObjectTypeFormatterList : public CommandObjectParsed {<br class="">
           }<br class="">
<br class="">
           any_printed = true;<br class="">
-          result.GetOutputStream().Printf("%s: %s\n",<br class="">
-                                          regex.GetText().str().c_str(),<br class="">
-                                          format_sp->GetDescription().c_str());<br class="">
+          result.GetOutputStream().Printf(<br class="">
+              "%s: %s\n", type_matcher.GetMatchString().GetCString(),<br class="">
+              format_sp->GetDescription().c_str());<br class="">
           return true;<br class="">
         });<br class="">
<br class="">
@@ -1681,10 +1686,10 @@ class CommandObjectTypeSummaryList<br class="">
     if (DataVisualization::NamedSummaryFormats::GetCount() > 0) {<br class="">
       result.GetOutputStream().Printf("Named summaries:\n");<br class="">
       DataVisualization::NamedSummaryFormats::ForEach(<br class="">
-          [&result](ConstString name,<br class="">
+          [&result](const TypeMatcher &type_matcher,<br class="">
                     const TypeSummaryImplSP &summary_sp) -> bool {<br class="">
             result.GetOutputStream().Printf(<br class="">
-                "%s: %s\n", name.AsCString(),<br class="">
+                "%s: %s\n", type_matcher.GetMatchString().GetCString(),<br class="">
                 summary_sp->GetDescription().c_str());<br class="">
             return true;<br class="">
           });<br class="">
<br class="">
diff  --git a/lldb/source/DataFormatters/DataVisualization.cpp b/lldb/source/DataFormatters/DataVisualization.cpp<br class="">
index 450a5cbc3ef3..82248bb64285 100644<br class="">
--- a/lldb/source/DataFormatters/DataVisualization.cpp<br class="">
+++ b/lldb/source/DataFormatters/DataVisualization.cpp<br class="">
@@ -174,8 +174,7 @@ bool DataVisualization::NamedSummaryFormats::GetSummaryFormat(<br class="">
<br class="">
 void DataVisualization::NamedSummaryFormats::Add(<br class="">
     ConstString type, const lldb::TypeSummaryImplSP &entry) {<br class="">
-  GetFormatManager().GetNamedSummaryContainer().Add(<br class="">
-      FormatManager::GetValidTypeName(type), entry);<br class="">
+  GetFormatManager().GetNamedSummaryContainer().Add(type, entry);<br class="">
 }<br class="">
<br class="">
 bool DataVisualization::NamedSummaryFormats::Delete(ConstString type) {<br class="">
@@ -187,7 +186,7 @@ void DataVisualization::NamedSummaryFormats::Clear() {<br class="">
 }<br class="">
<br class="">
 void DataVisualization::NamedSummaryFormats::ForEach(<br class="">
-    std::function<bool(ConstString, const lldb::TypeSummaryImplSP &)><br class="">
+    std::function<bool(const TypeMatcher &, const lldb::TypeSummaryImplSP &)><br class="">
         callback) {<br class="">
   GetFormatManager().GetNamedSummaryContainer().ForEach(callback);<br class="">
 }<br class="">
<br class="">
diff  --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp<br class="">
index ad02d37360b8..af6df3ae6b47 100644<br class="">
--- a/lldb/source/DataFormatters/FormatManager.cpp<br class="">
+++ b/lldb/source/DataFormatters/FormatManager.cpp<br class="">
@@ -551,10 +551,6 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) {<br class="">
   return true;<br class="">
 }<br class="">
<br class="">
-ConstString FormatManager::GetValidTypeName(ConstString type) {<br class="">
-  return ::GetValidTypeName_Impl(type);<br class="">
-}<br class="">
-<br class="">
 ConstString FormatManager::GetTypeForCache(ValueObject &valobj,<br class="">
                                            lldb::DynamicValueType use_dynamic) {<br class="">
   ValueObjectSP valobj_sp = valobj.GetQualifiedRepresentationIfAvailable(<br class="">
<br class="">
diff  --git a/lldb/unittests/DataFormatter/CMakeLists.txt b/lldb/unittests/DataFormatter/CMakeLists.txt<br class="">
index 45011c56b0b0..9d967a72bfd1 100644<br class="">
--- a/lldb/unittests/DataFormatter/CMakeLists.txt<br class="">
+++ b/lldb/unittests/DataFormatter/CMakeLists.txt<br class="">
@@ -1,5 +1,6 @@<br class="">
 add_lldb_unittest(LLDBFormatterTests<br class="">
   FormatManagerTests.cpp<br class="">
+  FormattersContainerTest.cpp<br class="">
   StringPrinterTests.cpp<br class="">
<br class="">
   LINK_LIBS<br class="">
<br class="">
diff  --git a/lldb/unittests/DataFormatter/FormattersContainerTest.cpp b/lldb/unittests/DataFormatter/FormattersContainerTest.cpp<br class="">
new file mode 100644<br class="">
index 000000000000..a28212391eae<br class="">
--- /dev/null<br class="">
+++ b/lldb/unittests/DataFormatter/FormattersContainerTest.cpp<br class="">
@@ -0,0 +1,159 @@<br class="">
+//===-- FormattersContainerTests.cpp --------------------------------------===//<br class="">
+//<br class="">
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br class="">
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank" class="">https://llvm.org/LICENSE.txt</a> for license information.<br class="">
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br class="">
+//<br class="">
+//===----------------------------------------------------------------------===//<br class="">
+<br class="">
+#include "lldb/DataFormatters/FormattersContainer.h"<br class="">
+<br class="">
+#include "gtest/gtest.h"<br class="">
+<br class="">
+using namespace lldb;<br class="">
+using namespace lldb_private;<br class="">
+<br class="">
+// All the prefixes that the exact name matching will strip from the type.<br class="">
+static const std::vector<std::string> exact_name_prefixes = {<br class="">
+    "", // no prefix.<br class="">
+    "class ", "struct ", "union ", "enum ",<br class="">
+};<br class="">
+<br class="">
+// TypeMatcher that uses a exact type name string that needs to be matched.<br class="">
+TEST(TypeMatcherTests, ExactName) {<br class="">
+  for (const std::string &prefix : exact_name_prefixes) {<br class="">
+    SCOPED_TRACE("Prefix: " + prefix);<br class="">
+<br class="">
+    TypeMatcher matcher(ConstString(prefix + "Name"));<br class="">
+    EXPECT_TRUE(matcher.Matches(ConstString("class Name")));<br class="">
+    EXPECT_TRUE(matcher.Matches(ConstString("struct Name")));<br class="">
+    EXPECT_TRUE(matcher.Matches(ConstString("union Name")));<br class="">
+    EXPECT_TRUE(matcher.Matches(ConstString("enum Name")));<br class="">
+    EXPECT_TRUE(matcher.Matches(ConstString("Name")));<br class="">
+<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("Name ")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("ame")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("Nam")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("am")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("a")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString(" ")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("class N")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("class ")));<br class="">
+    EXPECT_FALSE(matcher.Matches(ConstString("class")));<br class="">
+  }<br class="">
+}<br class="">
+<br class="">
+// TypeMatcher that uses a regex to match a type name.<br class="">
+TEST(TypeMatcherTests, RegexName) {<br class="">
+  TypeMatcher matcher(RegularExpression("^a[a-z]c$"));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString("abc")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString("azc")));<br class="">
+<br class="">
+  // FIXME: This isn't consistent with the 'exact' type name matches above.<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("class abc")));<br class="">
+<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("abbc")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString(" abc")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("abc ")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString(" abc ")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("XabcX")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("ac")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("aAc")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("ABC")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("")));<br class="">
+}<br class="">
+<br class="">
+// TypeMatcher that only searches the type name.<br class="">
+TEST(TypeMatcherTests, RegexMatchPart) {<br class="">
+  TypeMatcher matcher(RegularExpression("a[a-z]c"));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString("class abc")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString("abc")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString(" abc ")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString("azc")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString("abc ")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString(" abc ")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString(" abc")));<br class="">
+  EXPECT_TRUE(matcher.Matches(ConstString("XabcX")));<br class="">
+<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("abbc")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("ac")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("aAc")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("ABC")));<br class="">
+  EXPECT_FALSE(matcher.Matches(ConstString("")));<br class="">
+}<br class="">
+<br class="">
+// GetMatchString for exact type name matchers.<br class="">
+TEST(TypeMatcherTests, GetMatchStringExactName) {<br class="">
+  EXPECT_EQ(TypeMatcher(ConstString("aa")).GetMatchString(), "aa");<br class="">
+  EXPECT_EQ(TypeMatcher(ConstString("")).GetMatchString(), "");<br class="">
+  EXPECT_EQ(TypeMatcher(ConstString("[a]")).GetMatchString(), "[a]");<br class="">
+}<br class="">
+<br class="">
+// GetMatchString for regex matchers.<br class="">
+TEST(TypeMatcherTests, GetMatchStringRegex) {<br class="">
+  EXPECT_EQ(TypeMatcher(RegularExpression("aa")).GetMatchString(), "aa");<br class="">
+  EXPECT_EQ(TypeMatcher(RegularExpression("")).GetMatchString(), "");<br class="">
+  EXPECT_EQ(TypeMatcher(RegularExpression("[a]")).GetMatchString(), "[a]");<br class="">
+}<br class="">
+<br class="">
+// GetMatchString for regex matchers.<br class="">
+TEST(TypeMatcherTests, CreatedBySameMatchString) {<br class="">
+  TypeMatcher empty_str(ConstString(""));<br class="">
+  TypeMatcher empty_regex(RegularExpression(""));<br class="">
+  EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_str));<br class="">
+  EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_regex));<br class="">
+<br class="">
+  TypeMatcher a_str(ConstString("a"));<br class="">
+  TypeMatcher a_regex(RegularExpression("a"));<br class="">
+  EXPECT_TRUE(a_str.CreatedBySameMatchString(a_str));<br class="">
+  EXPECT_TRUE(a_str.CreatedBySameMatchString(a_regex));<br class="">
+<br class="">
+  TypeMatcher digit_str(ConstString("[0-9]"));<br class="">
+  TypeMatcher digit_regex(RegularExpression("[0-9]"));<br class="">
+  EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_str));<br class="">
+  EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_regex));<br class="">
+<br class="">
+  EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_str));<br class="">
+  EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_regex));<br class="">
+  EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_str));<br class="">
+  EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_regex));<br class="">
+<br class="">
+  EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_str));<br class="">
+  EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_regex));<br class="">
+  EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_str));<br class="">
+  EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_regex));<br class="">
+<br class="">
+  EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_str));<br class="">
+  EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_regex));<br class="">
+  EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_str));<br class="">
+  EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_regex));<br class="">
+<br class="">
+  EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_str));<br class="">
+  EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_regex));<br class="">
+  EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_str));<br class="">
+  EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_regex));<br class="">
+<br class="">
+  EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_str));<br class="">
+  EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_regex));<br class="">
+  EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_str));<br class="">
+  EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_regex));<br class="">
+<br class="">
+  EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_str));<br class="">
+  EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_regex));<br class="">
+  EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_str));<br class="">
+  EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_regex));<br class="">
+}<br class="">
+<br class="">
+// Test CreatedBySameMatchString with stripped exact name prefixes.<br class="">
+TEST(TypeMatcherTests, CreatedBySameMatchStringExactNamePrefixes) {<br class="">
+  for (const std::string &prefix : exact_name_prefixes) {<br class="">
+    SCOPED_TRACE("Prefix: " + prefix);<br class="">
+    TypeMatcher with_prefix(ConstString(prefix + "Name"));<br class="">
+    TypeMatcher without_prefix(RegularExpression(""));<br class="">
+<br class="">
+    EXPECT_TRUE(with_prefix.CreatedBySameMatchString(with_prefix));<br class="">
+    EXPECT_TRUE(without_prefix.CreatedBySameMatchString(without_prefix));<br class="">
+  }<br class="">
+}<br class="">
<br class="">
<br class="">
<br class="">
_______________________________________________<br class="">
lldb-commits mailing list<br class="">
<a href="mailto:lldb-commits@lists.llvm.org" target="_blank" class="">lldb-commits@lists.llvm.org</a><br class="">
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits" rel="noreferrer" target="_blank" class="">https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits</a><br class="">
</blockquote></div>
</div></blockquote></div><br class=""></div></body></html>