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