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
13using namespace lldb;
14using namespace lldb_private;
15
16TypeCategoryImpl::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
22static 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
60bool 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, valobj_lang: lang))
64 return true;
65 }
66 return false;
67}
68
69size_t TypeCategoryImpl::GetNumLanguages() {
70 if (m_languages.empty())
71 return 1;
72 return m_languages.size();
73}
74
75lldb::LanguageType TypeCategoryImpl::GetLanguageAtIndex(size_t idx) {
76 if (m_languages.empty())
77 return lldb::eLanguageTypeUnknown;
78 return m_languages[idx];
79}
80
81void TypeCategoryImpl::AddLanguage(lldb::LanguageType lang) {
82 m_languages.push_back(x: lang);
83}
84
85bool TypeCategoryImpl::Get(lldb::LanguageType lang,
86 const FormattersMatchVector &candidates,
87 lldb::TypeFormatImplSP &entry) {
88 if (!IsEnabled() || !IsApplicable(lang))
89 return false;
90 return m_format_cont.Get(candidates, entry);
91}
92
93bool TypeCategoryImpl::Get(lldb::LanguageType lang,
94 const FormattersMatchVector &candidates,
95 lldb::TypeSummaryImplSP &entry) {
96 if (!IsEnabled() || !IsApplicable(lang))
97 return false;
98 return m_summary_cont.Get(candidates, entry);
99}
100
101bool TypeCategoryImpl::Get(lldb::LanguageType lang,
102 const FormattersMatchVector &candidates,
103 lldb::SyntheticChildrenSP &entry) {
104 if (!IsEnabled() || !IsApplicable(lang))
105 return false;
106
107 // first find both Filter and Synth, and then check which is most recent
108 bool pick_synth = false;
109
110 TypeFilterImpl::SharedPointer filter_sp;
111 m_filter_cont.Get(candidates, entry&: filter_sp);
112
113 ScriptedSyntheticChildren::SharedPointer synth_sp;
114 m_synth_cont.Get(candidates, entry&: synth_sp);
115
116 if (!filter_sp.get() && !synth_sp.get())
117 return false;
118 else if (!filter_sp.get() && synth_sp.get())
119 pick_synth = true;
120 else if (filter_sp.get() && !synth_sp.get())
121 pick_synth = false;
122 else /*if (filter_sp.get() && synth_sp.get())*/
123 {
124 pick_synth = filter_sp->GetRevision() <= synth_sp->GetRevision();
125 }
126
127 if (pick_synth) {
128 entry = synth_sp;
129 return true;
130 } else {
131 entry = filter_sp;
132 return true;
133 }
134 return false;
135}
136
137void TypeCategoryImpl::Clear(FormatCategoryItems items) {
138 if (items & eFormatCategoryItemFormat)
139 m_format_cont.Clear();
140
141 if (items & eFormatCategoryItemSummary)
142 m_summary_cont.Clear();
143
144 if (items & eFormatCategoryItemFilter)
145 m_filter_cont.Clear();
146
147 if (items & eFormatCategoryItemSynth)
148 m_synth_cont.Clear();
149}
150
151bool TypeCategoryImpl::Delete(ConstString name, FormatCategoryItems items) {
152 bool success = false;
153
154 if (items & eFormatCategoryItemFormat)
155 success = m_format_cont.Delete(name) || success;
156
157 if (items & eFormatCategoryItemSummary)
158 success = m_summary_cont.Delete(name) || success;
159
160 if (items & eFormatCategoryItemFilter)
161 success = m_filter_cont.Delete(name) || success;
162
163 if (items & eFormatCategoryItemSynth)
164 success = m_synth_cont.Delete(name) || success;
165
166 return success;
167}
168
169uint32_t TypeCategoryImpl::GetCount(FormatCategoryItems items) {
170 uint32_t count = 0;
171
172 if (items & eFormatCategoryItemFormat)
173 count += m_format_cont.GetCount();
174
175 if (items & eFormatCategoryItemSummary)
176 count += m_summary_cont.GetCount();
177
178 if (items & eFormatCategoryItemFilter)
179 count += m_filter_cont.GetCount();
180
181 if (items & eFormatCategoryItemSynth)
182 count += m_synth_cont.GetCount();
183
184 return count;
185}
186
187bool TypeCategoryImpl::AnyMatches(
188 const FormattersMatchCandidate &candidate_type, FormatCategoryItems items,
189 bool only_enabled, const char **matching_category,
190 FormatCategoryItems *matching_type) {
191 if (!IsEnabled() && only_enabled)
192 return false;
193
194 if (items & eFormatCategoryItemFormat) {
195 if (m_format_cont.AnyMatches(candidate: candidate_type)) {
196 if (matching_category)
197 *matching_category = m_name.GetCString();
198 if (matching_type)
199 *matching_type = eFormatCategoryItemFormat;
200 return true;
201 }
202 }
203
204 if (items & eFormatCategoryItemSummary) {
205 if (m_summary_cont.AnyMatches(candidate: candidate_type)) {
206 if (matching_category)
207 *matching_category = m_name.GetCString();
208 if (matching_type)
209 *matching_type = eFormatCategoryItemSummary;
210 return true;
211 }
212 }
213
214 if (items & eFormatCategoryItemFilter) {
215 if (m_filter_cont.AnyMatches(candidate: candidate_type)) {
216 if (matching_category)
217 *matching_category = m_name.GetCString();
218 if (matching_type)
219 *matching_type = eFormatCategoryItemFilter;
220 return true;
221 }
222 }
223
224 if (items & eFormatCategoryItemSynth) {
225 if (m_synth_cont.AnyMatches(candidate: candidate_type)) {
226 if (matching_category)
227 *matching_category = m_name.GetCString();
228 if (matching_type)
229 *matching_type = eFormatCategoryItemSynth;
230 return true;
231 }
232 }
233
234 return false;
235}
236
237void TypeCategoryImpl::AutoComplete(CompletionRequest &request,
238 FormatCategoryItems items) {
239 if (items & eFormatCategoryItemFormat)
240 m_format_cont.AutoComplete(request);
241 if (items & eFormatCategoryItemSummary)
242 m_summary_cont.AutoComplete(request);
243 if (items & eFormatCategoryItemFilter)
244 m_filter_cont.AutoComplete(request);
245 if (items & eFormatCategoryItemSynth)
246 m_synth_cont.AutoComplete(request);
247}
248
249TypeCategoryImpl::FormatContainer::MapValueType
250TypeCategoryImpl::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) {
251 return m_format_cont.GetForTypeNameSpecifier(type_specifier_sp: type_sp);
252}
253
254TypeCategoryImpl::SummaryContainer::MapValueType
255TypeCategoryImpl::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) {
256 return m_summary_cont.GetForTypeNameSpecifier(type_specifier_sp: type_sp);
257}
258
259TypeCategoryImpl::FilterContainer::MapValueType
260TypeCategoryImpl::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) {
261 return m_filter_cont.GetForTypeNameSpecifier(type_specifier_sp: type_sp);
262}
263
264TypeCategoryImpl::SynthContainer::MapValueType
265TypeCategoryImpl::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) {
266 return m_synth_cont.GetForTypeNameSpecifier(type_specifier_sp: type_sp);
267}
268
269TypeCategoryImpl::FormatContainer::MapValueType
270TypeCategoryImpl::GetFormatAtIndex(size_t index) {
271 return m_format_cont.GetAtIndex(index);
272}
273
274TypeCategoryImpl::SummaryContainer::MapValueType
275TypeCategoryImpl::GetSummaryAtIndex(size_t index) {
276 return m_summary_cont.GetAtIndex(index);
277}
278
279TypeCategoryImpl::FilterContainer::MapValueType
280TypeCategoryImpl::GetFilterAtIndex(size_t index) {
281 return m_filter_cont.GetAtIndex(index);
282}
283
284TypeCategoryImpl::SynthContainer::MapValueType
285TypeCategoryImpl::GetSyntheticAtIndex(size_t index) {
286 return m_synth_cont.GetAtIndex(index);
287}
288
289lldb::TypeNameSpecifierImplSP
290TypeCategoryImpl::GetTypeNameSpecifierForFormatAtIndex(size_t index) {
291 return m_format_cont.GetTypeNameSpecifierAtIndex(index);
292}
293
294lldb::TypeNameSpecifierImplSP
295TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex(size_t index) {
296 return m_summary_cont.GetTypeNameSpecifierAtIndex(index);
297}
298
299lldb::TypeNameSpecifierImplSP
300TypeCategoryImpl::GetTypeNameSpecifierForFilterAtIndex(size_t index) {
301 return m_filter_cont.GetTypeNameSpecifierAtIndex(index);
302}
303
304lldb::TypeNameSpecifierImplSP
305TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex(size_t index) {
306 return m_synth_cont.GetTypeNameSpecifierAtIndex(index);
307}
308
309void TypeCategoryImpl::Enable(bool value, uint32_t position) {
310 std::lock_guard<std::recursive_mutex> guard(m_mutex);
311 if ((m_enabled = value))
312 m_enabled_position = position;
313 if (m_change_listener)
314 m_change_listener->Changed();
315}
316
317std::string TypeCategoryImpl::GetDescription() {
318 StreamString stream;
319 stream.Printf(format: "%s (%s", GetName(), (IsEnabled() ? "enabled" : "disabled"));
320 StreamString lang_stream;
321 lang_stream.Printf(format: ", applicable for language(s): ");
322 bool print_lang = false;
323 for (size_t idx = 0; idx < GetNumLanguages(); idx++) {
324 const lldb::LanguageType lang = GetLanguageAtIndex(idx);
325 if (lang != lldb::eLanguageTypeUnknown)
326 print_lang = true;
327 lang_stream.Printf(format: "%s%s", Language::GetNameForLanguageType(language: lang),
328 idx + 1 < GetNumLanguages() ? ", " : "");
329 }
330 if (print_lang)
331 stream.PutCString(cstr: lang_stream.GetString());
332 stream.PutChar(ch: ')');
333 return std::string(stream.GetString());
334}
335

source code of lldb/source/DataFormatters/TypeCategory.cpp