1//===-- TypeCategory.h ------------------------------------------*- 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#ifndef LLDB_DATAFORMATTERS_TYPECATEGORY_H
10#define LLDB_DATAFORMATTERS_TYPECATEGORY_H
11
12#include <array>
13#include <initializer_list>
14#include <memory>
15#include <mutex>
16#include <string>
17#include <vector>
18
19#include "lldb/lldb-enumerations.h"
20#include "lldb/lldb-public.h"
21
22#include "lldb/DataFormatters/FormatClasses.h"
23#include "lldb/DataFormatters/FormattersContainer.h"
24
25namespace lldb_private {
26
27// A formatter container with sub-containers for different priority tiers, that
28// also exposes a flat view of all formatters in it.
29//
30// Formatters have different priority during matching, depending on the type of
31// matching specified at registration. Exact matchers are processed first, then
32// regex, and finally callback matchers. However, the scripting API presents a
33// flat view of formatters in a category, with methods like `GetNumFormats()`
34// and `GetFormatAtIndex(i)`. So we need something that can behave like both
35// representations.
36template <typename FormatterImpl> class TieredFormatterContainer {
37public:
38 using Subcontainer = FormattersContainer<FormatterImpl>;
39 using SubcontainerSP = std::shared_ptr<Subcontainer>;
40 using ForEachCallback = typename Subcontainer::ForEachCallback;
41 using MapValueType = typename Subcontainer::ValueSP;
42
43 TieredFormatterContainer(IFormatChangeListener *change_listener) {
44 for (auto& sc : m_subcontainers)
45 sc = std::make_shared<Subcontainer>(change_listener);
46 }
47
48 /// Clears all subcontainers.
49 void Clear() {
50 for (auto sc : m_subcontainers)
51 sc->Clear();
52 }
53
54 /// Adds a formatter to the right subcontainer depending on the matching type
55 /// specified by `type_sp`.
56 void Add(lldb::TypeNameSpecifierImplSP type_sp,
57 std::shared_ptr<FormatterImpl> format_sp) {
58 m_subcontainers[type_sp->GetMatchType()]->Add(TypeMatcher(type_sp),
59 format_sp);
60 }
61
62 /// Deletes the formatter specified by `type_sp`.
63 bool Delete(lldb::TypeNameSpecifierImplSP type_sp) {
64 return m_subcontainers[type_sp->GetMatchType()]->Delete(
65 TypeMatcher(type_sp));
66 }
67
68 /// Deletes all formatters registered with the string `name`, in all
69 /// subcontainers.
70 bool Delete(ConstString name) {
71 bool success = false;
72 for (auto sc : m_subcontainers)
73 success = sc->Delete(name) || success;
74 return success;
75 }
76
77 /// Returns the total count of elements across all subcontainers.
78 uint32_t GetCount() {
79 uint32_t result = 0;
80 for (auto sc : m_subcontainers)
81 result += sc->GetCount();
82 return result;
83 }
84
85 /// Returns the formatter at `index`, simulating a flattened view of all
86 /// subcontainers in priority order.
87 MapValueType GetAtIndex(size_t index) {
88 for (auto sc : m_subcontainers) {
89 if (index < sc->GetCount())
90 return sc->GetAtIndex(index);
91 index -= sc->GetCount();
92 }
93 return MapValueType();
94 }
95
96 /// Looks for a matching candidate across all priority tiers, in priority
97 /// order. If a match is found, returns `true` and puts the matching entry in
98 /// `entry`.
99 bool Get(const FormattersMatchVector &candidates,
100 std::shared_ptr<FormatterImpl> &entry) {
101 for (auto sc : m_subcontainers) {
102 if (sc->Get(candidates, entry))
103 return true;
104 }
105 return false;
106 }
107
108 bool AnyMatches(const FormattersMatchCandidate &candidate) {
109 std::shared_ptr<FormatterImpl> entry;
110 for (auto sc : m_subcontainers) {
111 if (sc->Get(FormattersMatchVector{candidate}, entry))
112 return true;
113 }
114 return false;
115 }
116
117 /// Returns a formatter that is an exact match for `type_specifier_sp`. It
118 /// looks for a formatter with the same matching type that was created from
119 /// the same string. This is useful so we can refer to a formatter using the
120 /// same string used to register it.
121 ///
122 /// For example, `type_specifier_sp` can be something like
123 /// {"std::vector<.*>", eFormatterMatchRegex}, and we'd look for a regex
124 /// matcher with that exact regex string, NOT try to match that string using
125 /// regex.
126 MapValueType
127 GetForTypeNameSpecifier(lldb::TypeNameSpecifierImplSP type_specifier_sp) {
128 MapValueType retval;
129 if (type_specifier_sp) {
130 m_subcontainers[type_specifier_sp->GetMatchType()]->GetExact(
131 ConstString(type_specifier_sp->GetName()), retval);
132 }
133 return retval;
134 }
135
136 /// Returns the type name specifier at `index`, simulating a flattened view of
137 /// all subcontainers in priority order.
138 lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
139 for (auto sc : m_subcontainers) {
140 if (index < sc->GetCount())
141 return sc->GetTypeNameSpecifierAtIndex(index);
142 index -= sc->GetCount();
143 }
144 return lldb::TypeNameSpecifierImplSP();
145 }
146
147 /// Iterates through tiers in order, running `callback` on each element of
148 /// each tier.
149 void ForEach(std::function<bool(const TypeMatcher &,
150 const std::shared_ptr<FormatterImpl> &)>
151 callback) {
152 for (auto sc : m_subcontainers) {
153 sc->ForEach(callback);
154 }
155 }
156
157 void AutoComplete(CompletionRequest &request) {
158 for (auto sc: m_subcontainers)
159 sc->AutoComplete(request);
160 }
161
162 private:
163 std::array<std::shared_ptr<Subcontainer>, lldb::eLastFormatterMatchType + 1>
164 m_subcontainers;
165};
166
167class TypeCategoryImpl {
168private:
169 typedef TieredFormatterContainer<TypeFormatImpl> FormatContainer;
170 typedef TieredFormatterContainer<TypeSummaryImpl> SummaryContainer;
171 typedef TieredFormatterContainer<TypeFilterImpl> FilterContainer;
172 typedef TieredFormatterContainer<SyntheticChildren> SynthContainer;
173
174public:
175 typedef uint16_t FormatCategoryItems;
176 static const uint16_t ALL_ITEM_TYPES = UINT16_MAX;
177
178 // TypeFilterImpl inherits from SyntheticChildren, so we can't simply overload
179 // ForEach on the type of the callback because it would result in "call to
180 // member function 'ForEach' is ambiguous" errors. Instead we use this
181 // templated struct to hold the formatter type and the callback.
182 template<typename T>
183 struct ForEachCallback {
184 // Make it constructible from any callable that fits. This allows us to use
185 // lambdas a bit more easily at the call site. For example:
186 // ForEachCallback<TypeFormatImpl> callback = [](...) {...};
187 template <typename Callable> ForEachCallback(Callable c) : callback(c) {}
188 std::function<bool(const TypeMatcher &, const std::shared_ptr<T> &)>
189 callback;
190 };
191
192 TypeCategoryImpl(IFormatChangeListener *clist, ConstString name);
193
194 void ForEach(ForEachCallback<TypeFormatImpl> callback) {
195 m_format_cont.ForEach(callback: callback.callback);
196 }
197
198 void ForEach(ForEachCallback<TypeSummaryImpl> callback) {
199 m_summary_cont.ForEach(callback: callback.callback);
200 }
201
202 void ForEach(ForEachCallback<TypeFilterImpl> callback) {
203 m_filter_cont.ForEach(callback: callback.callback);
204 }
205
206 void ForEach(ForEachCallback<SyntheticChildren> callback) {
207 m_synth_cont.ForEach(callback: callback.callback);
208 }
209
210 FormatContainer::MapValueType
211 GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp);
212
213 SummaryContainer::MapValueType
214 GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp);
215
216 FilterContainer::MapValueType
217 GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp);
218
219 SynthContainer::MapValueType
220 GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp);
221
222 void AddTypeFormat(lldb::TypeNameSpecifierImplSP type_sp,
223 lldb::TypeFormatImplSP format_sp) {
224 m_format_cont.Add(type_sp, format_sp);
225 }
226
227 void AddTypeFormat(llvm::StringRef name, lldb::FormatterMatchType match_type,
228 lldb::TypeFormatImplSP format_sp) {
229 AddTypeFormat(
230 type_sp: std::make_shared<lldb_private::TypeNameSpecifierImpl>(args&: name, args&: match_type),
231 format_sp);
232 }
233
234 void AddTypeSummary(lldb::TypeNameSpecifierImplSP type_sp,
235 lldb::TypeSummaryImplSP summary_sp) {
236 m_summary_cont.Add(type_sp, format_sp: summary_sp);
237 }
238
239 void AddTypeSummary(llvm::StringRef name, lldb::FormatterMatchType match_type,
240 lldb::TypeSummaryImplSP summary_sp) {
241 AddTypeSummary(
242 type_sp: std::make_shared<lldb_private::TypeNameSpecifierImpl>(args&: name, args&: match_type),
243 summary_sp);
244 }
245
246 void AddTypeFilter(lldb::TypeNameSpecifierImplSP type_sp,
247 lldb::TypeFilterImplSP filter_sp) {
248 m_filter_cont.Add(type_sp, format_sp: filter_sp);
249 }
250
251 void AddTypeFilter(llvm::StringRef name, lldb::FormatterMatchType match_type,
252 lldb::TypeFilterImplSP filter_sp) {
253 AddTypeFilter(
254 type_sp: std::make_shared<lldb_private::TypeNameSpecifierImpl>(args&: name, args&: match_type),
255 filter_sp);
256 }
257
258 void AddTypeSynthetic(lldb::TypeNameSpecifierImplSP type_sp,
259 lldb::SyntheticChildrenSP synth_sp) {
260 m_synth_cont.Add(type_sp, format_sp: synth_sp);
261 }
262
263 void AddTypeSynthetic(llvm::StringRef name,
264 lldb::FormatterMatchType match_type,
265 lldb::SyntheticChildrenSP synth_sp) {
266 AddTypeSynthetic(
267 type_sp: std::make_shared<lldb_private::TypeNameSpecifierImpl>(args&: name, args&: match_type),
268 synth_sp);
269 }
270
271 bool DeleteTypeFormat(lldb::TypeNameSpecifierImplSP type_sp) {
272 return m_format_cont.Delete(type_sp);
273 }
274
275 bool DeleteTypeSummary(lldb::TypeNameSpecifierImplSP type_sp) {
276 return m_summary_cont.Delete(type_sp);
277 }
278
279 bool DeleteTypeFilter(lldb::TypeNameSpecifierImplSP type_sp) {
280 return m_filter_cont.Delete(type_sp);
281 }
282
283 bool DeleteTypeSynthetic(lldb::TypeNameSpecifierImplSP type_sp) {
284 return m_synth_cont.Delete(type_sp);
285 }
286
287 uint32_t GetNumFormats() { return m_format_cont.GetCount(); }
288
289 uint32_t GetNumSummaries() { return m_summary_cont.GetCount(); }
290
291 uint32_t GetNumFilters() { return m_filter_cont.GetCount(); }
292
293 uint32_t GetNumSynthetics() { return m_synth_cont.GetCount(); }
294
295 lldb::TypeNameSpecifierImplSP
296 GetTypeNameSpecifierForFormatAtIndex(size_t index);
297
298 lldb::TypeNameSpecifierImplSP
299 GetTypeNameSpecifierForSummaryAtIndex(size_t index);
300
301 lldb::TypeNameSpecifierImplSP
302 GetTypeNameSpecifierForFilterAtIndex(size_t index);
303
304 lldb::TypeNameSpecifierImplSP
305 GetTypeNameSpecifierForSyntheticAtIndex(size_t index);
306
307 FormatContainer::MapValueType GetFormatAtIndex(size_t index);
308
309 SummaryContainer::MapValueType GetSummaryAtIndex(size_t index);
310
311 FilterContainer::MapValueType GetFilterAtIndex(size_t index);
312
313 SynthContainer::MapValueType GetSyntheticAtIndex(size_t index);
314
315 bool IsEnabled() const { return m_enabled; }
316
317 uint32_t GetEnabledPosition() {
318 if (!m_enabled)
319 return UINT32_MAX;
320 else
321 return m_enabled_position;
322 }
323
324 bool Get(lldb::LanguageType lang, const FormattersMatchVector &candidates,
325 lldb::TypeFormatImplSP &entry);
326
327 bool Get(lldb::LanguageType lang, const FormattersMatchVector &candidates,
328 lldb::TypeSummaryImplSP &entry);
329
330 bool Get(lldb::LanguageType lang, const FormattersMatchVector &candidates,
331 lldb::SyntheticChildrenSP &entry);
332
333 void Clear(FormatCategoryItems items = ALL_ITEM_TYPES);
334
335 bool Delete(ConstString name, FormatCategoryItems items = ALL_ITEM_TYPES);
336
337 uint32_t GetCount(FormatCategoryItems items = ALL_ITEM_TYPES);
338
339 const char *GetName() { return m_name.GetCString(); }
340
341 size_t GetNumLanguages();
342
343 lldb::LanguageType GetLanguageAtIndex(size_t idx);
344
345 void AddLanguage(lldb::LanguageType lang);
346
347 std::string GetDescription();
348
349 bool AnyMatches(const FormattersMatchCandidate &candidate_type,
350 FormatCategoryItems items = ALL_ITEM_TYPES,
351 bool only_enabled = true,
352 const char **matching_category = nullptr,
353 FormatCategoryItems *matching_type = nullptr);
354
355 void AutoComplete(CompletionRequest &request, FormatCategoryItems items);
356
357 typedef std::shared_ptr<TypeCategoryImpl> SharedPointer;
358
359private:
360 FormatContainer m_format_cont;
361 SummaryContainer m_summary_cont;
362 FilterContainer m_filter_cont;
363 SynthContainer m_synth_cont;
364
365 bool m_enabled;
366
367 IFormatChangeListener *m_change_listener;
368
369 std::recursive_mutex m_mutex;
370
371 ConstString m_name;
372
373 std::vector<lldb::LanguageType> m_languages;
374
375 uint32_t m_enabled_position = 0;
376
377 void Enable(bool value, uint32_t position);
378
379 void Disable() { Enable(value: false, UINT32_MAX); }
380
381 bool IsApplicable(lldb::LanguageType lang);
382
383 uint32_t GetLastEnabledPosition() { return m_enabled_position; }
384
385 void SetEnabledPosition(uint32_t p) { m_enabled_position = p; }
386
387 friend class FormatManager;
388 friend class LanguageCategory;
389 friend class TypeCategoryMap;
390
391 friend class FormattersContainer<TypeFormatImpl>;
392
393 friend class FormattersContainer<TypeSummaryImpl>;
394
395 friend class FormattersContainer<TypeFilterImpl>;
396
397 friend class FormattersContainer<ScriptedSyntheticChildren>;
398};
399
400} // namespace lldb_private
401
402#endif // LLDB_DATAFORMATTERS_TYPECATEGORY_H
403

source code of lldb/include/lldb/DataFormatters/TypeCategory.h