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 
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 
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 
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 
69 size_t TypeCategoryImpl::GetNumLanguages() {
70   if (m_languages.empty())
71     return 1;
72   return m_languages.size();
73 }
74 
75 lldb::LanguageType TypeCategoryImpl::GetLanguageAtIndex(size_t idx) {
76   if (m_languages.empty())
77     return lldb::eLanguageTypeUnknown;
78   return m_languages[idx];
79 }
80 
81 void TypeCategoryImpl::AddLanguage(lldb::LanguageType lang) {
82   m_languages.push_back(lang);
83 }
84 
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 
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 
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 
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 
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 
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 
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
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
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
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
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
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
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
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
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
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
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
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
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 
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 
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