1 //===-- TypeCategory.cpp --------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "lldb/DataFormatters/TypeCategory.h"
10 #include "lldb/Target/Language.h"
11
12
13 using namespace lldb;
14 using namespace lldb_private;
15
TypeCategoryImpl(IFormatChangeListener * clist,ConstString name)16 TypeCategoryImpl::TypeCategoryImpl(IFormatChangeListener *clist,
17 ConstString name)
18 : m_format_cont(clist), m_summary_cont(clist), m_filter_cont(clist),
19 m_synth_cont(clist), m_enabled(false), m_change_listener(clist),
20 m_mutex(), m_name(name), m_languages() {}
21
IsApplicable(lldb::LanguageType category_lang,lldb::LanguageType valobj_lang)22 static bool IsApplicable(lldb::LanguageType category_lang,
23 lldb::LanguageType valobj_lang) {
24 switch (category_lang) {
25 // Unless we know better, allow only exact equality.
26 default:
27 return category_lang == valobj_lang;
28
29 // the C family, we consider it as one
30 case eLanguageTypeC89:
31 case eLanguageTypeC:
32 case eLanguageTypeC99:
33 return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
34 valobj_lang == eLanguageTypeC99;
35
36 // ObjC knows about C and itself
37 case eLanguageTypeObjC:
38 return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
39 valobj_lang == eLanguageTypeC99 || valobj_lang == eLanguageTypeObjC;
40
41 // C++ knows about C and C++
42 case eLanguageTypeC_plus_plus:
43 return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
44 valobj_lang == eLanguageTypeC99 ||
45 valobj_lang == eLanguageTypeC_plus_plus;
46
47 // ObjC++ knows about C,C++,ObjC and ObjC++
48 case eLanguageTypeObjC_plus_plus:
49 return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
50 valobj_lang == eLanguageTypeC99 ||
51 valobj_lang == eLanguageTypeC_plus_plus ||
52 valobj_lang == eLanguageTypeObjC;
53
54 // Categories with unspecified language match everything.
55 case eLanguageTypeUnknown:
56 return true;
57 }
58 }
59
IsApplicable(lldb::LanguageType lang)60 bool TypeCategoryImpl::IsApplicable(lldb::LanguageType lang) {
61 for (size_t idx = 0; idx < GetNumLanguages(); idx++) {
62 const lldb::LanguageType category_lang = GetLanguageAtIndex(idx);
63 if (::IsApplicable(category_lang, lang))
64 return true;
65 }
66 return false;
67 }
68
GetNumLanguages()69 size_t TypeCategoryImpl::GetNumLanguages() {
70 if (m_languages.empty())
71 return 1;
72 return m_languages.size();
73 }
74
GetLanguageAtIndex(size_t idx)75 lldb::LanguageType TypeCategoryImpl::GetLanguageAtIndex(size_t idx) {
76 if (m_languages.empty())
77 return lldb::eLanguageTypeUnknown;
78 return m_languages[idx];
79 }
80
AddLanguage(lldb::LanguageType lang)81 void TypeCategoryImpl::AddLanguage(lldb::LanguageType lang) {
82 m_languages.push_back(lang);
83 }
84
Get(lldb::LanguageType lang,const FormattersMatchVector & candidates,lldb::TypeFormatImplSP & entry)85 bool TypeCategoryImpl::Get(lldb::LanguageType lang,
86 const FormattersMatchVector &candidates,
87 lldb::TypeFormatImplSP &entry) {
88 if (!IsEnabled() || !IsApplicable(lang))
89 return false;
90 if (GetTypeFormatsContainer()->Get(candidates, entry))
91 return true;
92 bool regex = GetRegexTypeFormatsContainer()->Get(candidates, entry);
93 return regex;
94 }
95
Get(lldb::LanguageType lang,const FormattersMatchVector & candidates,lldb::TypeSummaryImplSP & entry)96 bool TypeCategoryImpl::Get(lldb::LanguageType lang,
97 const FormattersMatchVector &candidates,
98 lldb::TypeSummaryImplSP &entry) {
99 if (!IsEnabled() || !IsApplicable(lang))
100 return false;
101 if (GetTypeSummariesContainer()->Get(candidates, entry))
102 return true;
103 bool regex = GetRegexTypeSummariesContainer()->Get(candidates, entry);
104 return regex;
105 }
106
Get(lldb::LanguageType lang,const FormattersMatchVector & candidates,lldb::SyntheticChildrenSP & entry)107 bool TypeCategoryImpl::Get(lldb::LanguageType lang,
108 const FormattersMatchVector &candidates,
109 lldb::SyntheticChildrenSP &entry) {
110 if (!IsEnabled() || !IsApplicable(lang))
111 return false;
112 TypeFilterImpl::SharedPointer filter_sp;
113 // first find both Filter and Synth, and then check which is most recent
114
115 if (!GetTypeFiltersContainer()->Get(candidates, filter_sp))
116 GetRegexTypeFiltersContainer()->Get(candidates, filter_sp);
117
118 bool pick_synth = false;
119 ScriptedSyntheticChildren::SharedPointer synth;
120 if (!GetTypeSyntheticsContainer()->Get(candidates, synth))
121 GetRegexTypeSyntheticsContainer()->Get(candidates, synth);
122 if (!filter_sp.get() && !synth.get())
123 return false;
124 else if (!filter_sp.get() && synth.get())
125 pick_synth = true;
126
127 else if (filter_sp.get() && !synth.get())
128 pick_synth = false;
129
130 else /*if (filter_sp.get() && synth.get())*/
131 {
132 pick_synth = filter_sp->GetRevision() <= synth->GetRevision();
133 }
134 if (pick_synth) {
135 entry = synth;
136 return true;
137 } else {
138 entry = filter_sp;
139 return true;
140 }
141 return false;
142 }
143
Clear(FormatCategoryItems items)144 void TypeCategoryImpl::Clear(FormatCategoryItems items) {
145 if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue)
146 GetTypeFormatsContainer()->Clear();
147 if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue)
148 GetRegexTypeFormatsContainer()->Clear();
149
150 if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary)
151 GetTypeSummariesContainer()->Clear();
152 if ((items & eFormatCategoryItemRegexSummary) ==
153 eFormatCategoryItemRegexSummary)
154 GetRegexTypeSummariesContainer()->Clear();
155
156 if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter)
157 GetTypeFiltersContainer()->Clear();
158 if ((items & eFormatCategoryItemRegexFilter) ==
159 eFormatCategoryItemRegexFilter)
160 GetRegexTypeFiltersContainer()->Clear();
161
162 if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth)
163 GetTypeSyntheticsContainer()->Clear();
164 if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth)
165 GetRegexTypeSyntheticsContainer()->Clear();
166 }
167
Delete(ConstString name,FormatCategoryItems items)168 bool TypeCategoryImpl::Delete(ConstString name, FormatCategoryItems items) {
169 bool success = false;
170
171 if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue)
172 success = GetTypeFormatsContainer()->Delete(name) || success;
173 if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue)
174 success = GetRegexTypeFormatsContainer()->Delete(name) || success;
175
176 if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary)
177 success = GetTypeSummariesContainer()->Delete(name) || success;
178 if ((items & eFormatCategoryItemRegexSummary) ==
179 eFormatCategoryItemRegexSummary)
180 success = GetRegexTypeSummariesContainer()->Delete(name) || success;
181
182 if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter)
183 success = GetTypeFiltersContainer()->Delete(name) || success;
184 if ((items & eFormatCategoryItemRegexFilter) ==
185 eFormatCategoryItemRegexFilter)
186 success = GetRegexTypeFiltersContainer()->Delete(name) || success;
187
188 if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth)
189 success = GetTypeSyntheticsContainer()->Delete(name) || success;
190 if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth)
191 success = GetRegexTypeSyntheticsContainer()->Delete(name) || success;
192
193 return success;
194 }
195
GetCount(FormatCategoryItems items)196 uint32_t TypeCategoryImpl::GetCount(FormatCategoryItems items) {
197 uint32_t count = 0;
198
199 if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue)
200 count += GetTypeFormatsContainer()->GetCount();
201 if ((items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue)
202 count += GetRegexTypeFormatsContainer()->GetCount();
203
204 if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary)
205 count += GetTypeSummariesContainer()->GetCount();
206 if ((items & eFormatCategoryItemRegexSummary) ==
207 eFormatCategoryItemRegexSummary)
208 count += GetRegexTypeSummariesContainer()->GetCount();
209
210 if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter)
211 count += GetTypeFiltersContainer()->GetCount();
212 if ((items & eFormatCategoryItemRegexFilter) ==
213 eFormatCategoryItemRegexFilter)
214 count += GetRegexTypeFiltersContainer()->GetCount();
215
216 if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth)
217 count += GetTypeSyntheticsContainer()->GetCount();
218 if ((items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth)
219 count += GetRegexTypeSyntheticsContainer()->GetCount();
220
221 return count;
222 }
223
AnyMatches(ConstString type_name,FormatCategoryItems items,bool only_enabled,const char ** matching_category,FormatCategoryItems * matching_type)224 bool TypeCategoryImpl::AnyMatches(ConstString type_name,
225 FormatCategoryItems items, bool only_enabled,
226 const char **matching_category,
227 FormatCategoryItems *matching_type) {
228 if (!IsEnabled() && only_enabled)
229 return false;
230
231 lldb::TypeFormatImplSP format_sp;
232 lldb::TypeSummaryImplSP summary_sp;
233 TypeFilterImpl::SharedPointer filter_sp;
234 ScriptedSyntheticChildren::SharedPointer synth_sp;
235
236 if ((items & eFormatCategoryItemValue) == eFormatCategoryItemValue) {
237 if (GetTypeFormatsContainer()->Get(type_name, format_sp)) {
238 if (matching_category)
239 *matching_category = m_name.GetCString();
240 if (matching_type)
241 *matching_type = eFormatCategoryItemValue;
242 return true;
243 }
244 }
245 if ((items & eFormatCategoryItemRegexValue) ==
246 eFormatCategoryItemRegexValue) {
247 if (GetRegexTypeFormatsContainer()->Get(type_name, format_sp)) {
248 if (matching_category)
249 *matching_category = m_name.GetCString();
250 if (matching_type)
251 *matching_type = eFormatCategoryItemRegexValue;
252 return true;
253 }
254 }
255
256 if ((items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary) {
257 if (GetTypeSummariesContainer()->Get(type_name, summary_sp)) {
258 if (matching_category)
259 *matching_category = m_name.GetCString();
260 if (matching_type)
261 *matching_type = eFormatCategoryItemSummary;
262 return true;
263 }
264 }
265 if ((items & eFormatCategoryItemRegexSummary) ==
266 eFormatCategoryItemRegexSummary) {
267 if (GetRegexTypeSummariesContainer()->Get(type_name, summary_sp)) {
268 if (matching_category)
269 *matching_category = m_name.GetCString();
270 if (matching_type)
271 *matching_type = eFormatCategoryItemRegexSummary;
272 return true;
273 }
274 }
275
276 if ((items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter) {
277 if (GetTypeFiltersContainer()->Get(type_name, filter_sp)) {
278 if (matching_category)
279 *matching_category = m_name.GetCString();
280 if (matching_type)
281 *matching_type = eFormatCategoryItemFilter;
282 return true;
283 }
284 }
285 if ((items & eFormatCategoryItemRegexFilter) ==
286 eFormatCategoryItemRegexFilter) {
287 if (GetRegexTypeFiltersContainer()->Get(type_name, filter_sp)) {
288 if (matching_category)
289 *matching_category = m_name.GetCString();
290 if (matching_type)
291 *matching_type = eFormatCategoryItemRegexFilter;
292 return true;
293 }
294 }
295
296 if ((items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth) {
297 if (GetTypeSyntheticsContainer()->Get(type_name, synth_sp)) {
298 if (matching_category)
299 *matching_category = m_name.GetCString();
300 if (matching_type)
301 *matching_type = eFormatCategoryItemSynth;
302 return true;
303 }
304 }
305 if ((items & eFormatCategoryItemRegexSynth) ==
306 eFormatCategoryItemRegexSynth) {
307 if (GetRegexTypeSyntheticsContainer()->Get(type_name, synth_sp)) {
308 if (matching_category)
309 *matching_category = m_name.GetCString();
310 if (matching_type)
311 *matching_type = eFormatCategoryItemRegexSynth;
312 return true;
313 }
314 }
315
316 return false;
317 }
318
319 TypeCategoryImpl::FormatContainer::MapValueType
GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp)320 TypeCategoryImpl::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) {
321 FormatContainer::MapValueType retval;
322
323 if (type_sp) {
324 if (type_sp->IsRegex())
325 GetRegexTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()),
326 retval);
327 else
328 GetTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()),
329 retval);
330 }
331
332 return retval;
333 }
334
335 TypeCategoryImpl::SummaryContainer::MapValueType
GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp)336 TypeCategoryImpl::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) {
337 SummaryContainer::MapValueType retval;
338
339 if (type_sp) {
340 if (type_sp->IsRegex())
341 GetRegexTypeSummariesContainer()->GetExact(
342 ConstString(type_sp->GetName()), retval);
343 else
344 GetTypeSummariesContainer()->GetExact(ConstString(type_sp->GetName()),
345 retval);
346 }
347
348 return retval;
349 }
350
351 TypeCategoryImpl::FilterContainer::MapValueType
GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp)352 TypeCategoryImpl::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) {
353 FilterContainer::MapValueType retval;
354
355 if (type_sp) {
356 if (type_sp->IsRegex())
357 GetRegexTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()),
358 retval);
359 else
360 GetTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()),
361 retval);
362 }
363
364 return retval;
365 }
366
367 TypeCategoryImpl::SynthContainer::MapValueType
GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp)368 TypeCategoryImpl::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) {
369 SynthContainer::MapValueType retval;
370
371 if (type_sp) {
372 if (type_sp->IsRegex())
373 GetRegexTypeSyntheticsContainer()->GetExact(
374 ConstString(type_sp->GetName()), retval);
375 else
376 GetTypeSyntheticsContainer()->GetExact(ConstString(type_sp->GetName()),
377 retval);
378 }
379
380 return retval;
381 }
382
383 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForSummaryAtIndex(size_t index)384 TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex(size_t index) {
385 if (index < GetTypeSummariesContainer()->GetCount())
386 return GetTypeSummariesContainer()->GetTypeNameSpecifierAtIndex(index);
387 else
388 return GetRegexTypeSummariesContainer()->GetTypeNameSpecifierAtIndex(
389 index - GetTypeSummariesContainer()->GetCount());
390 }
391
392 TypeCategoryImpl::FormatContainer::MapValueType
GetFormatAtIndex(size_t index)393 TypeCategoryImpl::GetFormatAtIndex(size_t index) {
394 if (index < GetTypeFormatsContainer()->GetCount())
395 return GetTypeFormatsContainer()->GetAtIndex(index);
396 else
397 return GetRegexTypeFormatsContainer()->GetAtIndex(
398 index - GetTypeFormatsContainer()->GetCount());
399 }
400
401 TypeCategoryImpl::SummaryContainer::MapValueType
GetSummaryAtIndex(size_t index)402 TypeCategoryImpl::GetSummaryAtIndex(size_t index) {
403 if (index < GetTypeSummariesContainer()->GetCount())
404 return GetTypeSummariesContainer()->GetAtIndex(index);
405 else
406 return GetRegexTypeSummariesContainer()->GetAtIndex(
407 index - GetTypeSummariesContainer()->GetCount());
408 }
409
410 TypeCategoryImpl::FilterContainer::MapValueType
GetFilterAtIndex(size_t index)411 TypeCategoryImpl::GetFilterAtIndex(size_t index) {
412 if (index < GetTypeFiltersContainer()->GetCount())
413 return GetTypeFiltersContainer()->GetAtIndex(index);
414 else
415 return GetRegexTypeFiltersContainer()->GetAtIndex(
416 index - GetTypeFiltersContainer()->GetCount());
417 }
418
419 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForFormatAtIndex(size_t index)420 TypeCategoryImpl::GetTypeNameSpecifierForFormatAtIndex(size_t index) {
421 if (index < GetTypeFormatsContainer()->GetCount())
422 return GetTypeFormatsContainer()->GetTypeNameSpecifierAtIndex(index);
423 else
424 return GetRegexTypeFormatsContainer()->GetTypeNameSpecifierAtIndex(
425 index - GetTypeFormatsContainer()->GetCount());
426 }
427
428 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForFilterAtIndex(size_t index)429 TypeCategoryImpl::GetTypeNameSpecifierForFilterAtIndex(size_t index) {
430 if (index < GetTypeFiltersContainer()->GetCount())
431 return GetTypeFiltersContainer()->GetTypeNameSpecifierAtIndex(index);
432 else
433 return GetRegexTypeFiltersContainer()->GetTypeNameSpecifierAtIndex(
434 index - GetTypeFiltersContainer()->GetCount());
435 }
436
437 TypeCategoryImpl::SynthContainer::MapValueType
GetSyntheticAtIndex(size_t index)438 TypeCategoryImpl::GetSyntheticAtIndex(size_t index) {
439 if (index < GetTypeSyntheticsContainer()->GetCount())
440 return GetTypeSyntheticsContainer()->GetAtIndex(index);
441 else
442 return GetRegexTypeSyntheticsContainer()->GetAtIndex(
443 index - GetTypeSyntheticsContainer()->GetCount());
444 }
445
446 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierForSyntheticAtIndex(size_t index)447 TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex(size_t index) {
448 if (index < GetTypeSyntheticsContainer()->GetCount())
449 return GetTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex(index);
450 else
451 return GetRegexTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex(
452 index - GetTypeSyntheticsContainer()->GetCount());
453 }
454
Enable(bool value,uint32_t position)455 void TypeCategoryImpl::Enable(bool value, uint32_t position) {
456 std::lock_guard<std::recursive_mutex> guard(m_mutex);
457 if ((m_enabled = value))
458 m_enabled_position = position;
459 if (m_change_listener)
460 m_change_listener->Changed();
461 }
462
GetDescription()463 std::string TypeCategoryImpl::GetDescription() {
464 StreamString stream;
465 stream.Printf("%s (%s", GetName(), (IsEnabled() ? "enabled" : "disabled"));
466 StreamString lang_stream;
467 lang_stream.Printf(", applicable for language(s): ");
468 bool print_lang = false;
469 for (size_t idx = 0; idx < GetNumLanguages(); idx++) {
470 const lldb::LanguageType lang = GetLanguageAtIndex(idx);
471 if (lang != lldb::eLanguageTypeUnknown)
472 print_lang = true;
473 lang_stream.Printf("%s%s", Language::GetNameForLanguageType(lang),
474 idx + 1 < GetNumLanguages() ? ", " : "");
475 }
476 if (print_lang)
477 stream.PutCString(lang_stream.GetString());
478 stream.PutChar(')');
479 return std::string(stream.GetString());
480 }
481