static void Clear();
- static void
- ForEach(std::function<bool(ConstString, const lldb::TypeSummaryImplSP &)>
- callback);
+ static void ForEach(std::function<bool(const TypeMatcher &,
+ const lldb::TypeSummaryImplSP &)>
+ callback);
static uint32_t GetCount();
};
// this file's objects directly
class FormatManager : public IFormatChangeListener {
- typedef FormatMap<ConstString, TypeSummaryImpl> NamedSummariesMap;
+ typedef FormatMap<TypeSummaryImpl> NamedSummariesMap;
typedef TypeCategoryMap::MapType::iterator CategoryMapIterator;
public:
static const char *GetFormatAsCString(lldb::Format format);
- // if the user tries to add formatters for, say, "struct Foo" those will not
- // match any type because of the way we strip qualifiers from typenames this
- // method looks for the case where the user is adding a
- // "class","struct","enum" or "union" Foo and strips the unnecessary
- // qualifier
- static ConstString GetValidTypeName(ConstString type);
-
// when DataExtractor dumps a vectorOfT, it uses a predefined format for each
// item this method returns it, or eFormatInvalid if vector_format is not a
// vectorOf
virtual uint32_t GetCurrentRevision() = 0;
};
-// if the user tries to add formatters for, say, "struct Foo" those will not
-// match any type because of the way we strip qualifiers from typenames this
-// method looks for the case where the user is adding a "class","struct","enum"
-// or "union" Foo and strips the unnecessary qualifier
-static inline ConstString GetValidTypeName_Impl(ConstString type) {
- if (type.IsEmpty())
- return type;
-
- std::string type_cstr(type.AsCString());
- StringLexer type_lexer(type_cstr);
+/// Class for matching type names.
+class TypeMatcher {
+ RegularExpression m_type_name_regex;
+ ConstString m_type_name;
+ /// False if m_type_name_regex should be used for matching. False if this is
+ /// just matching by comparing with m_type_name string.
+ bool m_is_regex;
+
+ // if the user tries to add formatters for, say, "struct Foo" those will not
+ // match any type because of the way we strip qualifiers from typenames this
+ // method looks for the case where the user is adding a
+ // "class","struct","enum" or "union" Foo and strips the unnecessary qualifier
+ static ConstString StripTypeName(ConstString type) {
+ if (type.IsEmpty())
+ return type;
+
+ std::string type_cstr(type.AsCString());
+ StringLexer type_lexer(type_cstr);
+
+ type_lexer.AdvanceIf("class ");
+ type_lexer.AdvanceIf("enum ");
+ type_lexer.AdvanceIf("struct ");
+ type_lexer.AdvanceIf("union ");
+
+ while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
+ ;
+
+ return ConstString(type_lexer.GetUnlexed());
+ }
- type_lexer.AdvanceIf("class ");
- type_lexer.AdvanceIf("enum ");
- type_lexer.AdvanceIf("struct ");
- type_lexer.AdvanceIf("union ");
+public:
+ 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_is_regex(false) {}
+ /// Creates a matcher that accepts any type matching the given regex.
+ TypeMatcher(RegularExpression regex)
+ : m_type_name_regex(regex), m_is_regex(true) {}
+
+ /// True iff this matches the given type name.
+ bool Matches(ConstString type_name) const {
+ if (m_is_regex)
+ return m_type_name_regex.Execute(type_name.GetStringRef());
+ return m_type_name == type_name ||
+ StripTypeName(m_type_name) == StripTypeName(type_name);
+ }
- while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
- ;
+ /// Returns the underlying match string for this TypeMatcher.
+ ConstString GetMatchString() const {
+ if (m_is_regex)
+ return ConstString(m_type_name_regex.GetText());
+ return StripTypeName(m_type_name);
+ }
- return ConstString(type_lexer.GetUnlexed());
-}
+ /// Returns true if this TypeMatcher and the given one were most created by
+ /// the same match string.
+ /// The main purpose of this function is to find existing TypeMatcher
+ /// instances by the user input that created them. This is necessary as LLDB
+ /// allows referencing existing TypeMatchers in commands by the user input
+ /// that originally created them:
+ /// (lldb) type summary add --summary-string \"A\" -x TypeName
+ /// (lldb) type summary delete TypeName
+ bool CreatedBySameMatchString(TypeMatcher other) const {
+ return GetMatchString() == other.GetMatchString();
+ }
+};
-template <typename KeyType, typename ValueType> class FormattersContainer;
+template <typename ValueType> class FormattersContainer;
-template <typename KeyType, typename ValueType> class FormatMap {
+template <typename ValueType> class FormatMap {
public:
typedef typename ValueType::SharedPointer ValueSP;
- typedef std::vector<std::pair<KeyType, ValueSP>> MapType;
+ typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType;
typedef typename MapType::iterator MapIterator;
- typedef std::function<bool(const KeyType &, const ValueSP &)> ForEachCallback;
+ typedef std::function<bool(const TypeMatcher &, const ValueSP &)>
+ ForEachCallback;
FormatMap(IFormatChangeListener *lst)
: m_map(), m_map_mutex(), listener(lst) {}
- void Add(KeyType name, const ValueSP &entry) {
+ void Add(TypeMatcher matcher, const ValueSP &entry) {
if (listener)
entry->GetRevision() = listener->GetCurrentRevision();
else
entry->GetRevision() = 0;
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
- Delete(name);
- m_map.emplace_back(std::move(name), std::move(entry));
+ Delete(matcher);
+ m_map.emplace_back(std::move(matcher), std::move(entry));
if (listener)
listener->Changed();
}
- bool Delete(const KeyType &name) {
+ bool Delete(const TypeMatcher &matcher) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
for (MapIterator iter = m_map.begin(); iter != m_map.end(); ++iter)
- if (iter->first == name) {
+ if (iter->first.CreatedBySameMatchString(matcher)) {
m_map.erase(iter);
if (listener)
listener->Changed();
listener->Changed();
}
- bool Get(const KeyType &name, ValueSP &entry) {
+ bool Get(const TypeMatcher &matcher, ValueSP &entry) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
for (const auto &pos : m_map)
- if (pos.first == name) {
+ if (pos.first.CreatedBySameMatchString(matcher)) {
entry = pos.second;
return true;
}
if (callback) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
for (const auto &pos : m_map) {
- const KeyType &type = pos.first;
+ const TypeMatcher &type = pos.first;
if (!callback(type, pos.second))
break;
}
}
// If caller holds the mutex we could return a reference without copy ctor.
- KeyType GetKeyAtIndex(size_t index) {
+ llvm::Optional<TypeMatcher> GetKeyAtIndex(size_t index) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
if (index >= m_map.size())
- return {};
+ return llvm::None;
return m_map[index].first;
}
std::recursive_mutex &mutex() { return m_map_mutex; }
- friend class FormattersContainer<KeyType, ValueType>;
+ friend class FormattersContainer<ValueType>;
friend class FormatManager;
};
-template <typename KeyType, typename ValueType> class FormattersContainer {
+template <typename ValueType> class FormattersContainer {
protected:
- typedef FormatMap<KeyType, ValueType> BackEndType;
+ typedef FormatMap<ValueType> BackEndType;
public:
- typedef typename BackEndType::MapType MapType;
- typedef typename MapType::iterator MapIterator;
- typedef KeyType MapKeyType;
typedef std::shared_ptr<ValueType> MapValueType;
typedef typename BackEndType::ForEachCallback ForEachCallback;
- typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>>
+ typedef typename std::shared_ptr<FormattersContainer<ValueType>>
SharedPointer;
friend class TypeCategoryImpl;
FormattersContainer(IFormatChangeListener *lst) : m_format_map(lst) {}
- void Add(MapKeyType type, const MapValueType &entry) {
- Add_Impl(std::move(type), entry, static_cast<KeyType *>(nullptr));
+ void Add(TypeMatcher type, const MapValueType &entry) {
+ m_format_map.Add(std::move(type), entry);
}
- bool Delete(ConstString type) {
- return Delete_Impl(type, static_cast<KeyType *>(nullptr));
- }
+ bool Delete(TypeMatcher type) { return m_format_map.Delete(type); }
bool Get(ConstString type, MapValueType &entry) {
- return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
+ std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
+ for (auto &formatter : llvm::reverse(m_format_map.map())) {
+ if (formatter.first.Matches(type)) {
+ entry = formatter.second;
+ return true;
+ }
+ }
+ return false;
}
bool GetExact(ConstString type, MapValueType &entry) {
- return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));
+ return m_format_map.Get(type, entry);
}
MapValueType GetAtIndex(size_t index) {
}
lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
- return GetTypeNameSpecifierAtIndex_Impl(index,
- static_cast<KeyType *>(nullptr));
+ llvm::Optional<TypeMatcher> type_matcher =
+ m_format_map.GetKeyAtIndex(index);
+ if (!type_matcher)
+ return lldb::TypeNameSpecifierImplSP();
+ return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(
+ type_matcher->GetMatchString().GetStringRef(), true));
}
void Clear() { m_format_map.Clear(); }
FormattersContainer(const FormattersContainer &) = delete;
const FormattersContainer &operator=(const FormattersContainer &) = delete;
- void Add_Impl(MapKeyType type, const MapValueType &entry,
- RegularExpression *dummy) {
- m_format_map.Add(std::move(type), entry);
- }
-
- void Add_Impl(ConstString type, const MapValueType &entry,
- ConstString *dummy) {
- m_format_map.Add(GetValidTypeName_Impl(type), entry);
- }
-
- bool Delete_Impl(ConstString type, ConstString *dummy) {
- return m_format_map.Delete(type);
- }
-
- bool Delete_Impl(ConstString type, RegularExpression *dummy) {
- std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
- MapIterator pos, end = m_format_map.map().end();
- for (pos = m_format_map.map().begin(); pos != end; pos++) {
- const RegularExpression ®ex = pos->first;
- if (type.GetStringRef() == regex.GetText()) {
- m_format_map.map().erase(pos);
- if (m_format_map.listener)
- m_format_map.listener->Changed();
- return true;
- }
- }
- return false;
- }
-
- bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {
- return m_format_map.Get(type, entry);
- }
-
- bool GetExact_Impl(ConstString type, MapValueType &entry,
- ConstString *dummy) {
- return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
- }
-
- lldb::TypeNameSpecifierImplSP
- GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) {
- ConstString key = m_format_map.GetKeyAtIndex(index);
- if (key)
- return lldb::TypeNameSpecifierImplSP(
- new TypeNameSpecifierImpl(key.GetStringRef(), false));
- else
- return lldb::TypeNameSpecifierImplSP();
- }
-
- lldb::TypeNameSpecifierImplSP
- GetTypeNameSpecifierAtIndex_Impl(size_t index, RegularExpression *dummy) {
- RegularExpression regex = m_format_map.GetKeyAtIndex(index);
- if (regex == RegularExpression())
- return lldb::TypeNameSpecifierImplSP();
- return lldb::TypeNameSpecifierImplSP(
- new TypeNameSpecifierImpl(regex.GetText().str().c_str(), true));
- }
-
- bool Get_Impl(ConstString key, MapValueType &value,
- RegularExpression *dummy) {
- llvm::StringRef key_str = key.GetStringRef();
- std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
- // Patterns are matched in reverse-chronological order.
- for (const auto &pos : llvm::reverse(m_format_map.map())) {
- const RegularExpression ®ex = pos.first;
- if (regex.Execute(key_str)) {
- value = pos.second;
- return true;
- }
- }
- return false;
- }
-
- bool GetExact_Impl(ConstString key, MapValueType &value,
- RegularExpression *dummy) {
- std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
- for (const auto &pos : m_format_map.map()) {
- const RegularExpression ®ex = pos.first;
- if (regex.GetText() == key.GetStringRef()) {
- value = pos.second;
- return true;
- }
- }
- return false;
- }
-
bool Get(const FormattersMatchVector &candidates, MapValueType &entry) {
for (const FormattersMatchCandidate &candidate : candidates) {
if (Get(candidate.GetTypeName(), entry)) {
template <typename FormatterImpl> class FormatterContainerPair {
public:
- typedef FormattersContainer<ConstString, FormatterImpl> ExactMatchContainer;
- typedef FormattersContainer<RegularExpression, FormatterImpl>
- RegexMatchContainer;
+ typedef FormattersContainer<FormatterImpl> ExactMatchContainer;
+ typedef FormattersContainer<FormatterImpl> RegexMatchContainer;
- typedef typename ExactMatchContainer::MapType ExactMatchMap;
- typedef typename RegexMatchContainer::MapType RegexMatchMap;
+ typedef TypeMatcher ExactMatchMap;
+ typedef TypeMatcher RegexMatchMap;
typedef typename ExactMatchContainer::MapValueType MapValueType;
friend class LanguageCategory;
friend class TypeCategoryMap;
- friend class FormattersContainer<ConstString, TypeFormatImpl>;
- friend class FormattersContainer<lldb::RegularExpressionSP, TypeFormatImpl>;
+ friend class FormattersContainer<TypeFormatImpl>;
- friend class FormattersContainer<ConstString, TypeSummaryImpl>;
- friend class FormattersContainer<lldb::RegularExpressionSP, TypeSummaryImpl>;
+ friend class FormattersContainer<TypeSummaryImpl>;
- friend class FormattersContainer<ConstString, TypeFilterImpl>;
- friend class FormattersContainer<lldb::RegularExpressionSP, TypeFilterImpl>;
-
- friend class FormattersContainer<ConstString, ScriptedSyntheticChildren>;
- friend class FormattersContainer<lldb::RegularExpressionSP,
- ScriptedSyntheticChildren>;
+ friend class FormattersContainer<TypeFilterImpl>;
+ friend class FormattersContainer<ScriptedSyntheticChildren>;
};
} // namespace lldb_private
std::recursive_mutex &mutex() { return m_map_mutex; }
- friend class FormattersContainer<KeyType, ValueType>;
+ friend class FormattersContainer<ValueType>;
friend class FormatManager;
};
} // namespace lldb_private
TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach;
foreach
.SetExact([&result, &formatter_regex, &any_printed](
- ConstString name,
+ const TypeMatcher &type_matcher,
const FormatterSharedPointer &format_sp) -> bool {
if (formatter_regex) {
bool escape = true;
- if (name.GetStringRef() == formatter_regex->GetText()) {
+ if (type_matcher.CreatedBySameMatchString(
+ ConstString(formatter_regex->GetText()))) {
escape = false;
- } else if (formatter_regex->Execute(name.GetStringRef())) {
+ } else if (formatter_regex->Execute(
+ type_matcher.GetMatchString().GetStringRef())) {
escape = false;
}
}
any_printed = true;
- result.GetOutputStream().Printf("%s: %s\n", name.AsCString(),
- format_sp->GetDescription().c_str());
+ result.GetOutputStream().Printf(
+ "%s: %s\n", type_matcher.GetMatchString().GetCString(),
+ format_sp->GetDescription().c_str());
return true;
});
foreach
.SetWithRegex([&result, &formatter_regex, &any_printed](
- const RegularExpression ®ex,
+ const TypeMatcher &type_matcher,
const FormatterSharedPointer &format_sp) -> bool {
if (formatter_regex) {
bool escape = true;
- if (regex.GetText() == formatter_regex->GetText()) {
+ if (type_matcher.CreatedBySameMatchString(
+ ConstString(formatter_regex->GetText()))) {
escape = false;
- } else if (formatter_regex->Execute(regex.GetText())) {
+ } else if (formatter_regex->Execute(
+ type_matcher.GetMatchString().GetStringRef())) {
escape = false;
}
}
any_printed = true;
- result.GetOutputStream().Printf("%s: %s\n",
- regex.GetText().str().c_str(),
- format_sp->GetDescription().c_str());
+ result.GetOutputStream().Printf(
+ "%s: %s\n", type_matcher.GetMatchString().GetCString(),
+ format_sp->GetDescription().c_str());
return true;
});
if (DataVisualization::NamedSummaryFormats::GetCount() > 0) {
result.GetOutputStream().Printf("Named summaries:\n");
DataVisualization::NamedSummaryFormats::ForEach(
- [&result](ConstString name,
+ [&result](const TypeMatcher &type_matcher,
const TypeSummaryImplSP &summary_sp) -> bool {
result.GetOutputStream().Printf(
- "%s: %s\n", name.AsCString(),
+ "%s: %s\n", type_matcher.GetMatchString().GetCString(),
summary_sp->GetDescription().c_str());
return true;
});
void DataVisualization::NamedSummaryFormats::Add(
ConstString type, const lldb::TypeSummaryImplSP &entry) {
- GetFormatManager().GetNamedSummaryContainer().Add(
- FormatManager::GetValidTypeName(type), entry);
+ GetFormatManager().GetNamedSummaryContainer().Add(type, entry);
}
bool DataVisualization::NamedSummaryFormats::Delete(ConstString type) {
}
void DataVisualization::NamedSummaryFormats::ForEach(
- std::function<bool(ConstString, const lldb::TypeSummaryImplSP &)>
+ std::function<bool(const TypeMatcher &, const lldb::TypeSummaryImplSP &)>
callback) {
GetFormatManager().GetNamedSummaryContainer().ForEach(callback);
}
return true;
}
-ConstString FormatManager::GetValidTypeName(ConstString type) {
- return ::GetValidTypeName_Impl(type);
-}
-
ConstString FormatManager::GetTypeForCache(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
ValueObjectSP valobj_sp = valobj.GetQualifiedRepresentationIfAvailable(
add_lldb_unittest(LLDBFormatterTests
FormatManagerTests.cpp
+ FormattersContainerTest.cpp
StringPrinterTests.cpp
LINK_LIBS
--- /dev/null
+//===-- FormattersContainerTests.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/DataFormatters/FormattersContainer.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// All the prefixes that the exact name matching will strip from the type.
+static const std::vector<std::string> exact_name_prefixes = {
+ "", // no prefix.
+ "class ", "struct ", "union ", "enum ",
+};
+
+// TypeMatcher that uses a exact type name string that needs to be matched.
+TEST(TypeMatcherTests, ExactName) {
+ for (const std::string &prefix : exact_name_prefixes) {
+ 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")));
+ }
+}
+
+// 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")));
+
+ // 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("")));
+}
+
+// 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("")));
+}
+
+// GetMatchString for exact type name matchers.
+TEST(TypeMatcherTests, GetMatchStringExactName) {
+ EXPECT_EQ(TypeMatcher(ConstString("aa")).GetMatchString(), "aa");
+ EXPECT_EQ(TypeMatcher(ConstString("")).GetMatchString(), "");
+ EXPECT_EQ(TypeMatcher(ConstString("[a]")).GetMatchString(), "[a]");
+}
+
+// GetMatchString for regex matchers.
+TEST(TypeMatcherTests, GetMatchStringRegex) {
+ EXPECT_EQ(TypeMatcher(RegularExpression("aa")).GetMatchString(), "aa");
+ EXPECT_EQ(TypeMatcher(RegularExpression("")).GetMatchString(), "");
+ EXPECT_EQ(TypeMatcher(RegularExpression("[a]")).GetMatchString(), "[a]");
+}
+
+// GetMatchString for regex matchers.
+TEST(TypeMatcherTests, CreatedBySameMatchString) {
+ TypeMatcher empty_str(ConstString(""));
+ TypeMatcher empty_regex(RegularExpression(""));
+ EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_str));
+ EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_regex));
+
+ TypeMatcher a_str(ConstString("a"));
+ TypeMatcher a_regex(RegularExpression("a"));
+ EXPECT_TRUE(a_str.CreatedBySameMatchString(a_str));
+ EXPECT_TRUE(a_str.CreatedBySameMatchString(a_regex));
+
+ TypeMatcher digit_str(ConstString("[0-9]"));
+ TypeMatcher digit_regex(RegularExpression("[0-9]"));
+ EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_str));
+ EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_regex));
+
+ EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_str));
+ EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_regex));
+ EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_str));
+ EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_regex));
+
+ EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_str));
+ EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_regex));
+ EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_str));
+ EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_regex));
+
+ EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_str));
+ EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_regex));
+ EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_str));
+ EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_regex));
+
+ EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_str));
+ EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_regex));
+ EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_str));
+ EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_regex));
+
+ EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_str));
+ EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_regex));
+ EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_str));
+ EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_regex));
+
+ EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_str));
+ EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_regex));
+ EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_str));
+ EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_regex));
+}
+
+// Test CreatedBySameMatchString with stripped exact name prefixes.
+TEST(TypeMatcherTests, CreatedBySameMatchStringExactNamePrefixes) {
+ for (const std::string &prefix : exact_name_prefixes) {
+ SCOPED_TRACE("Prefix: " + prefix);
+ TypeMatcher with_prefix(ConstString(prefix + "Name"));
+ TypeMatcher without_prefix(RegularExpression(""));
+
+ EXPECT_TRUE(with_prefix.CreatedBySameMatchString(with_prefix));
+ EXPECT_TRUE(without_prefix.CreatedBySameMatchString(without_prefix));
+ }
+}