Skip to content

Commit d1a9078

Browse files
committed
[LLDB] Add optional callback function to TypeMatcher
1 parent e64f8e0 commit d1a9078

File tree

3 files changed

+109
-23
lines changed

3 files changed

+109
-23
lines changed

lldb/include/lldb/DataFormatters/FormatClasses.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,16 @@ class FormattersMatchData {
149149
CandidateLanguagesVector m_candidate_languages;
150150
};
151151

152+
using CxxTypeCandidateMatchFn = bool(const FormattersMatchCandidate &);
153+
152154
class TypeNameSpecifierImpl {
153155
public:
154156
TypeNameSpecifierImpl() = default;
155157

156158
TypeNameSpecifierImpl(llvm::StringRef name,
157-
lldb::FormatterMatchType match_type)
158-
: m_match_type(match_type) {
159+
lldb::FormatterMatchType match_type,
160+
CxxTypeCandidateMatchFn *match_fn = nullptr)
161+
: m_match_type(match_type), m_match_fn(match_fn) {
159162
m_type.m_type_name = std::string(name);
160163
}
161164

@@ -188,6 +191,8 @@ class TypeNameSpecifierImpl {
188191
return CompilerType();
189192
}
190193

194+
CxxTypeCandidateMatchFn *GetCxxMatchFunction() const { return m_match_fn; }
195+
191196
lldb::FormatterMatchType GetMatchType() { return m_match_type; }
192197

193198
bool IsRegex() { return m_match_type == lldb::eFormatterMatchRegex; }
@@ -200,6 +205,7 @@ class TypeNameSpecifierImpl {
200205
CompilerType m_compiler_type;
201206
};
202207
TypeOrName m_type;
208+
CxxTypeCandidateMatchFn *m_match_fn = nullptr;
203209

204210
TypeNameSpecifierImpl(const TypeNameSpecifierImpl &) = delete;
205211
const TypeNameSpecifierImpl &

lldb/include/lldb/DataFormatters/FormattersContainer.h

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ class TypeMatcher {
5050
/// - eFormatterMatchCallback: run the function in m_name to decide if a type
5151
/// matches or not.
5252
lldb::FormatterMatchType m_match_type;
53+
/// An optional additional check for a FormattersMatchCandidate.
54+
///
55+
/// If set, the name/regex is still checked first and this function will be
56+
/// called if the name matches.
57+
CxxTypeCandidateMatchFn *m_match_fn = nullptr;
5358

5459
// if the user tries to add formatters for, say, "struct Foo" those will not
5560
// match any type because of the way we strip qualifiers from typenames this
@@ -86,32 +91,19 @@ class TypeMatcher {
8691
/// name specifier.
8792
TypeMatcher(lldb::TypeNameSpecifierImplSP type_specifier)
8893
: m_name(type_specifier->GetName()),
89-
m_match_type(type_specifier->GetMatchType()) {
94+
m_match_type(type_specifier->GetMatchType()),
95+
m_match_fn(type_specifier->GetCxxMatchFunction()) {
9096
if (m_match_type == lldb::eFormatterMatchRegex)
9197
m_type_name_regex = RegularExpression(type_specifier->GetName());
9298
}
9399

94100
/// True iff this matches the given type.
95101
bool Matches(FormattersMatchCandidate candidate_type) const {
96-
ConstString type_name = candidate_type.GetTypeName();
97-
switch (m_match_type) {
98-
case lldb::eFormatterMatchExact:
99-
return m_name == type_name ||
100-
StripTypeName(m_name) == StripTypeName(type_name);
101-
case lldb::eFormatterMatchRegex:
102-
return m_type_name_regex.Execute(type_name.GetStringRef());
103-
case lldb::eFormatterMatchCallback:
104-
// CommandObjectType{Synth,Filter}Add tries to prevent the user from
105-
// creating both a synthetic child provider and a filter for the same type
106-
// in the same category, but we don't have a type object at that point, so
107-
// it creates a dummy candidate without type or script interpreter.
108-
// Skip callback matching in these cases.
109-
if (candidate_type.GetScriptInterpreter())
110-
return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
111-
m_name.AsCString(),
112-
std::make_shared<TypeImpl>(candidate_type.GetType()));
113-
}
114-
return false;
102+
if (!MatchesName(candidate_type))
103+
return false;
104+
if (m_match_fn && !m_match_fn(candidate_type))
105+
return false;
106+
return true;
115107
}
116108

117109
lldb::FormatterMatchType GetMatchType() const { return m_match_type; }
@@ -134,7 +126,31 @@ class TypeMatcher {
134126
/// (lldb) type summary add --summary-string \"A\" -x TypeName
135127
/// (lldb) type summary delete TypeName
136128
bool CreatedBySameMatchString(TypeMatcher other) const {
137-
return GetMatchString() == other.GetMatchString();
129+
return GetMatchString() == other.GetMatchString() &&
130+
m_match_fn == other.m_match_fn;
131+
}
132+
133+
private:
134+
bool MatchesName(FormattersMatchCandidate candidate_type) const {
135+
ConstString type_name = candidate_type.GetTypeName();
136+
switch (m_match_type) {
137+
case lldb::eFormatterMatchExact:
138+
return m_name == type_name ||
139+
StripTypeName(m_name) == StripTypeName(type_name);
140+
case lldb::eFormatterMatchRegex:
141+
return m_type_name_regex.Execute(type_name.GetStringRef());
142+
case lldb::eFormatterMatchCallback:
143+
// CommandObjectType{Synth,Filter}Add tries to prevent the user from
144+
// creating both a synthetic child provider and a filter for the same type
145+
// in the same category, but we don't have a type object at that point, so
146+
// it creates a dummy candidate without type or script interpreter.
147+
// Skip callback matching in these cases.
148+
if (candidate_type.GetScriptInterpreter())
149+
return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
150+
m_name.AsCString(),
151+
std::make_shared<TypeImpl>(candidate_type.GetType()));
152+
}
153+
return false;
138154
}
139155
};
140156

lldb/unittests/DataFormatter/FormattersContainerTest.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,67 @@ TEST(TypeMatcherTests, CreatedBySameMatchStringExactNamePrefixes) {
165165
EXPECT_TRUE(without_prefix.CreatedBySameMatchString(without_prefix));
166166
}
167167
}
168+
169+
TEST(TypeMatcherTests, CxxTypeCandidateMatchTest) {
170+
auto alwaysTrue = +[](const FormattersMatchCandidate &) { return true; };
171+
auto alwaysFalse = +[](const FormattersMatchCandidate &) { return false; };
172+
173+
TypeMatcher regex_matcher_true(std::make_shared<TypeNameSpecifierImpl>(
174+
"^a[a-z]c$", eFormatterMatchRegex, alwaysTrue));
175+
EXPECT_TRUE(regex_matcher_true.Matches(CandidateFromTypeName("abc")));
176+
EXPECT_TRUE(regex_matcher_true.Matches(CandidateFromTypeName("azc")));
177+
EXPECT_FALSE(regex_matcher_true.Matches(CandidateFromTypeName("a")));
178+
179+
TypeMatcher regex_matcher_false(std::make_shared<TypeNameSpecifierImpl>(
180+
"^a[a-z]c$", eFormatterMatchRegex, alwaysFalse));
181+
EXPECT_FALSE(regex_matcher_false.Matches(CandidateFromTypeName("abc")));
182+
EXPECT_FALSE(regex_matcher_false.Matches(CandidateFromTypeName("azc")));
183+
EXPECT_FALSE(regex_matcher_false.Matches(CandidateFromTypeName("a")));
184+
185+
TypeMatcher string_matcher_true(std::make_shared<TypeNameSpecifierImpl>(
186+
"abc", eFormatterMatchExact, alwaysTrue));
187+
EXPECT_TRUE(string_matcher_true.Matches(CandidateFromTypeName("abc")));
188+
EXPECT_FALSE(string_matcher_true.Matches(CandidateFromTypeName("azc")));
189+
EXPECT_FALSE(string_matcher_true.Matches(CandidateFromTypeName("a")));
190+
191+
TypeMatcher string_matcher_false(std::make_shared<TypeNameSpecifierImpl>(
192+
"abc", eFormatterMatchExact, alwaysFalse));
193+
EXPECT_FALSE(string_matcher_false.Matches(CandidateFromTypeName("abc")));
194+
EXPECT_FALSE(string_matcher_false.Matches(CandidateFromTypeName("azc")));
195+
EXPECT_FALSE(string_matcher_false.Matches(CandidateFromTypeName("a")));
196+
197+
EXPECT_TRUE(regex_matcher_true.CreatedBySameMatchString(regex_matcher_true));
198+
EXPECT_FALSE(
199+
regex_matcher_true.CreatedBySameMatchString(regex_matcher_false));
200+
EXPECT_FALSE(
201+
regex_matcher_true.CreatedBySameMatchString(string_matcher_true));
202+
EXPECT_FALSE(
203+
regex_matcher_true.CreatedBySameMatchString(string_matcher_false));
204+
205+
EXPECT_FALSE(
206+
regex_matcher_false.CreatedBySameMatchString(regex_matcher_true));
207+
EXPECT_TRUE(
208+
regex_matcher_false.CreatedBySameMatchString(regex_matcher_false));
209+
EXPECT_FALSE(
210+
regex_matcher_false.CreatedBySameMatchString(string_matcher_true));
211+
EXPECT_FALSE(
212+
regex_matcher_false.CreatedBySameMatchString(string_matcher_false));
213+
214+
EXPECT_FALSE(
215+
string_matcher_true.CreatedBySameMatchString(regex_matcher_true));
216+
EXPECT_FALSE(
217+
string_matcher_true.CreatedBySameMatchString(regex_matcher_false));
218+
EXPECT_TRUE(
219+
string_matcher_true.CreatedBySameMatchString(string_matcher_true));
220+
EXPECT_FALSE(
221+
string_matcher_true.CreatedBySameMatchString(string_matcher_false));
222+
223+
EXPECT_FALSE(
224+
string_matcher_false.CreatedBySameMatchString(regex_matcher_true));
225+
EXPECT_FALSE(
226+
string_matcher_false.CreatedBySameMatchString(regex_matcher_false));
227+
EXPECT_FALSE(
228+
string_matcher_false.CreatedBySameMatchString(string_matcher_true));
229+
EXPECT_TRUE(
230+
string_matcher_false.CreatedBySameMatchString(string_matcher_false));
231+
}

0 commit comments

Comments
 (0)