1 //===-- FormatManager.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/DataFormatters/FormatManager.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/DataFormatters/FormattersHelpers.h"
13 #include "lldb/DataFormatters/LanguageCategory.h"
14 #include "lldb/Interpreter/ScriptInterpreter.h"
15 #include "lldb/Target/ExecutionContext.h"
16 #include "lldb/Target/Language.h"
17 #include "lldb/Utility/LLDBLog.h"
18 #include "lldb/Utility/Log.h"
19 #include "llvm/ADT/STLExtras.h"
22 using namespace lldb_private
;
23 using namespace lldb_private::formatters
;
27 const char format_char
; // One or more format characters that can be used for
29 const char *format_name
; // Long format name that can be used to specify the
33 static constexpr FormatInfo g_format_infos
[] = {
34 {eFormatDefault
, '\0', "default"},
35 {eFormatBoolean
, 'B', "boolean"},
36 {eFormatBinary
, 'b', "binary"},
37 {eFormatBytes
, 'y', "bytes"},
38 {eFormatBytesWithASCII
, 'Y', "bytes with ASCII"},
39 {eFormatChar
, 'c', "character"},
40 {eFormatCharPrintable
, 'C', "printable character"},
41 {eFormatComplexFloat
, 'F', "complex float"},
42 {eFormatCString
, 's', "c-string"},
43 {eFormatDecimal
, 'd', "decimal"},
44 {eFormatEnum
, 'E', "enumeration"},
45 {eFormatHex
, 'x', "hex"},
46 {eFormatHexUppercase
, 'X', "uppercase hex"},
47 {eFormatFloat
, 'f', "float"},
48 {eFormatOctal
, 'o', "octal"},
49 {eFormatOSType
, 'O', "OSType"},
50 {eFormatUnicode16
, 'U', "unicode16"},
51 {eFormatUnicode32
, '\0', "unicode32"},
52 {eFormatUnsigned
, 'u', "unsigned decimal"},
53 {eFormatPointer
, 'p', "pointer"},
54 {eFormatVectorOfChar
, '\0', "char[]"},
55 {eFormatVectorOfSInt8
, '\0', "int8_t[]"},
56 {eFormatVectorOfUInt8
, '\0', "uint8_t[]"},
57 {eFormatVectorOfSInt16
, '\0', "int16_t[]"},
58 {eFormatVectorOfUInt16
, '\0', "uint16_t[]"},
59 {eFormatVectorOfSInt32
, '\0', "int32_t[]"},
60 {eFormatVectorOfUInt32
, '\0', "uint32_t[]"},
61 {eFormatVectorOfSInt64
, '\0', "int64_t[]"},
62 {eFormatVectorOfUInt64
, '\0', "uint64_t[]"},
63 {eFormatVectorOfFloat16
, '\0', "float16[]"},
64 {eFormatVectorOfFloat32
, '\0', "float32[]"},
65 {eFormatVectorOfFloat64
, '\0', "float64[]"},
66 {eFormatVectorOfUInt128
, '\0', "uint128_t[]"},
67 {eFormatComplexInteger
, 'I', "complex integer"},
68 {eFormatCharArray
, 'a', "character array"},
69 {eFormatAddressInfo
, 'A', "address"},
70 {eFormatHexFloat
, '\0', "hex float"},
71 {eFormatInstruction
, 'i', "instruction"},
72 {eFormatVoid
, 'v', "void"},
73 {eFormatUnicode8
, 'u', "unicode8"},
76 static_assert((sizeof(g_format_infos
) / sizeof(g_format_infos
[0])) ==
78 "All formats must have a corresponding info entry.");
80 static uint32_t g_num_format_infos
= std::size(g_format_infos
);
82 static bool GetFormatFromFormatChar(char format_char
, Format
&format
) {
83 for (uint32_t i
= 0; i
< g_num_format_infos
; ++i
) {
84 if (g_format_infos
[i
].format_char
== format_char
) {
85 format
= g_format_infos
[i
].format
;
89 format
= eFormatInvalid
;
93 static bool GetFormatFromFormatName(llvm::StringRef format_name
,
94 bool partial_match_ok
, Format
&format
) {
96 for (i
= 0; i
< g_num_format_infos
; ++i
) {
97 if (format_name
.equals_insensitive(g_format_infos
[i
].format_name
)) {
98 format
= g_format_infos
[i
].format
;
103 if (partial_match_ok
) {
104 for (i
= 0; i
< g_num_format_infos
; ++i
) {
105 if (llvm::StringRef(g_format_infos
[i
].format_name
)
106 .starts_with_insensitive(format_name
)) {
107 format
= g_format_infos
[i
].format
;
112 format
= eFormatInvalid
;
116 void FormatManager::Changed() {
118 m_format_cache
.Clear();
119 std::lock_guard
<std::recursive_mutex
> guard(m_language_categories_mutex
);
120 for (auto &iter
: m_language_categories_map
) {
122 iter
.second
->GetFormatCache().Clear();
126 bool FormatManager::GetFormatFromCString(const char *format_cstr
,
127 bool partial_match_ok
,
128 lldb::Format
&format
) {
129 bool success
= false;
130 if (format_cstr
&& format_cstr
[0]) {
131 if (format_cstr
[1] == '\0') {
132 success
= GetFormatFromFormatChar(format_cstr
[0], format
);
137 success
= GetFormatFromFormatName(format_cstr
, partial_match_ok
, format
);
140 format
= eFormatInvalid
;
144 char FormatManager::GetFormatAsFormatChar(lldb::Format format
) {
145 for (uint32_t i
= 0; i
< g_num_format_infos
; ++i
) {
146 if (g_format_infos
[i
].format
== format
)
147 return g_format_infos
[i
].format_char
;
152 const char *FormatManager::GetFormatAsCString(Format format
) {
153 if (format
>= eFormatDefault
&& format
< kNumFormats
)
154 return g_format_infos
[format
].format_name
;
158 void FormatManager::EnableAllCategories() {
159 m_categories_map
.EnableAllCategories();
160 std::lock_guard
<std::recursive_mutex
> guard(m_language_categories_mutex
);
161 for (auto &iter
: m_language_categories_map
) {
163 iter
.second
->Enable();
167 void FormatManager::DisableAllCategories() {
168 m_categories_map
.DisableAllCategories();
169 std::lock_guard
<std::recursive_mutex
> guard(m_language_categories_mutex
);
170 for (auto &iter
: m_language_categories_map
) {
172 iter
.second
->Disable();
176 void FormatManager::GetPossibleMatches(
177 ValueObject
&valobj
, CompilerType compiler_type
,
178 lldb::DynamicValueType use_dynamic
, FormattersMatchVector
&entries
,
179 FormattersMatchCandidate::Flags current_flags
, bool root_level
) {
180 compiler_type
= compiler_type
.GetTypeForFormatters();
181 ConstString
type_name(compiler_type
.GetTypeName());
182 ScriptInterpreter
*script_interpreter
=
183 valobj
.GetTargetSP()->GetDebugger().GetScriptInterpreter();
184 if (valobj
.GetBitfieldBitSize() > 0) {
185 StreamString sstring
;
186 sstring
.Printf("%s:%d", type_name
.AsCString(), valobj
.GetBitfieldBitSize());
187 ConstString
bitfieldname(sstring
.GetString());
188 entries
.push_back({bitfieldname
, script_interpreter
,
189 TypeImpl(compiler_type
), current_flags
});
192 if (!compiler_type
.IsMeaninglessWithoutDynamicResolution()) {
193 entries
.push_back({type_name
, script_interpreter
, TypeImpl(compiler_type
),
196 ConstString
display_type_name(compiler_type
.GetTypeName());
197 if (display_type_name
!= type_name
)
198 entries
.push_back({display_type_name
, script_interpreter
,
199 TypeImpl(compiler_type
), current_flags
});
202 for (bool is_rvalue_ref
= true, j
= true;
203 j
&& compiler_type
.IsReferenceType(nullptr, &is_rvalue_ref
); j
= false) {
204 CompilerType non_ref_type
= compiler_type
.GetNonReferenceType();
205 GetPossibleMatches(valobj
, non_ref_type
, use_dynamic
, entries
,
206 current_flags
.WithStrippedReference());
207 if (non_ref_type
.IsTypedefType()) {
208 CompilerType deffed_referenced_type
= non_ref_type
.GetTypedefedType();
209 deffed_referenced_type
=
210 is_rvalue_ref
? deffed_referenced_type
.GetRValueReferenceType()
211 : deffed_referenced_type
.GetLValueReferenceType();
212 // this is not exactly the usual meaning of stripping typedefs
214 valobj
, deffed_referenced_type
,
215 use_dynamic
, entries
, current_flags
.WithStrippedTypedef());
219 if (compiler_type
.IsPointerType()) {
220 CompilerType non_ptr_type
= compiler_type
.GetPointeeType();
221 GetPossibleMatches(valobj
, non_ptr_type
, use_dynamic
, entries
,
222 current_flags
.WithStrippedPointer());
223 if (non_ptr_type
.IsTypedefType()) {
224 CompilerType deffed_pointed_type
=
225 non_ptr_type
.GetTypedefedType().GetPointerType();
226 // this is not exactly the usual meaning of stripping typedefs
227 GetPossibleMatches(valobj
, deffed_pointed_type
, use_dynamic
, entries
,
228 current_flags
.WithStrippedTypedef());
232 // For arrays with typedef-ed elements, we add a candidate with the typedef
235 if (compiler_type
.IsArrayType(nullptr, &array_size
, nullptr)) {
236 ExecutionContext
exe_ctx(valobj
.GetExecutionContextRef());
237 CompilerType element_type
= compiler_type
.GetArrayElementType(
238 exe_ctx
.GetBestExecutionContextScope());
239 if (element_type
.IsTypedefType()) {
240 // Get the stripped element type and compute the stripped array type
242 CompilerType deffed_array_type
=
243 element_type
.GetTypedefedType().GetArrayType(array_size
);
244 // this is not exactly the usual meaning of stripping typedefs
246 valobj
, deffed_array_type
,
247 use_dynamic
, entries
, current_flags
.WithStrippedTypedef());
251 for (lldb::LanguageType language_type
:
252 GetCandidateLanguages(valobj
.GetObjectRuntimeLanguage())) {
253 if (Language
*language
= Language::FindPlugin(language_type
)) {
254 for (const FormattersMatchCandidate
& candidate
:
255 language
->GetPossibleFormattersMatches(valobj
, use_dynamic
)) {
256 entries
.push_back(candidate
);
261 // try to strip typedef chains
262 if (compiler_type
.IsTypedefType()) {
263 CompilerType deffed_type
= compiler_type
.GetTypedefedType();
264 GetPossibleMatches(valobj
, deffed_type
, use_dynamic
, entries
,
265 current_flags
.WithStrippedTypedef());
270 if (!compiler_type
.IsValid())
273 CompilerType unqual_compiler_ast_type
=
274 compiler_type
.GetFullyUnqualifiedType();
275 if (!unqual_compiler_ast_type
.IsValid())
277 if (unqual_compiler_ast_type
.GetOpaqueQualType() !=
278 compiler_type
.GetOpaqueQualType())
279 GetPossibleMatches(valobj
, unqual_compiler_ast_type
, use_dynamic
,
280 entries
, current_flags
);
283 // if all else fails, go to static type
284 if (valobj
.IsDynamic()) {
285 lldb::ValueObjectSP
static_value_sp(valobj
.GetStaticValue());
287 GetPossibleMatches(*static_value_sp
.get(),
288 static_value_sp
->GetCompilerType(), use_dynamic
,
289 entries
, current_flags
, true);
294 lldb::TypeFormatImplSP
295 FormatManager::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp
) {
297 return lldb::TypeFormatImplSP();
298 lldb::TypeFormatImplSP format_chosen_sp
;
299 uint32_t num_categories
= m_categories_map
.GetCount();
300 lldb::TypeCategoryImplSP category_sp
;
301 uint32_t prio_category
= UINT32_MAX
;
302 for (uint32_t category_id
= 0; category_id
< num_categories
; category_id
++) {
303 category_sp
= GetCategoryAtIndex(category_id
);
304 if (!category_sp
->IsEnabled())
306 lldb::TypeFormatImplSP format_current_sp
=
307 category_sp
->GetFormatForType(type_sp
);
308 if (format_current_sp
&&
309 (format_chosen_sp
.get() == nullptr ||
310 (prio_category
> category_sp
->GetEnabledPosition()))) {
311 prio_category
= category_sp
->GetEnabledPosition();
312 format_chosen_sp
= format_current_sp
;
315 return format_chosen_sp
;
318 lldb::TypeSummaryImplSP
319 FormatManager::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp
) {
321 return lldb::TypeSummaryImplSP();
322 lldb::TypeSummaryImplSP summary_chosen_sp
;
323 uint32_t num_categories
= m_categories_map
.GetCount();
324 lldb::TypeCategoryImplSP category_sp
;
325 uint32_t prio_category
= UINT32_MAX
;
326 for (uint32_t category_id
= 0; category_id
< num_categories
; category_id
++) {
327 category_sp
= GetCategoryAtIndex(category_id
);
328 if (!category_sp
->IsEnabled())
330 lldb::TypeSummaryImplSP summary_current_sp
=
331 category_sp
->GetSummaryForType(type_sp
);
332 if (summary_current_sp
&&
333 (summary_chosen_sp
.get() == nullptr ||
334 (prio_category
> category_sp
->GetEnabledPosition()))) {
335 prio_category
= category_sp
->GetEnabledPosition();
336 summary_chosen_sp
= summary_current_sp
;
339 return summary_chosen_sp
;
342 lldb::TypeFilterImplSP
343 FormatManager::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp
) {
345 return lldb::TypeFilterImplSP();
346 lldb::TypeFilterImplSP filter_chosen_sp
;
347 uint32_t num_categories
= m_categories_map
.GetCount();
348 lldb::TypeCategoryImplSP category_sp
;
349 uint32_t prio_category
= UINT32_MAX
;
350 for (uint32_t category_id
= 0; category_id
< num_categories
; category_id
++) {
351 category_sp
= GetCategoryAtIndex(category_id
);
352 if (!category_sp
->IsEnabled())
354 lldb::TypeFilterImplSP
filter_current_sp(
355 (TypeFilterImpl
*)category_sp
->GetFilterForType(type_sp
).get());
356 if (filter_current_sp
&&
357 (filter_chosen_sp
.get() == nullptr ||
358 (prio_category
> category_sp
->GetEnabledPosition()))) {
359 prio_category
= category_sp
->GetEnabledPosition();
360 filter_chosen_sp
= filter_current_sp
;
363 return filter_chosen_sp
;
366 lldb::ScriptedSyntheticChildrenSP
367 FormatManager::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp
) {
369 return lldb::ScriptedSyntheticChildrenSP();
370 lldb::ScriptedSyntheticChildrenSP synth_chosen_sp
;
371 uint32_t num_categories
= m_categories_map
.GetCount();
372 lldb::TypeCategoryImplSP category_sp
;
373 uint32_t prio_category
= UINT32_MAX
;
374 for (uint32_t category_id
= 0; category_id
< num_categories
; category_id
++) {
375 category_sp
= GetCategoryAtIndex(category_id
);
376 if (!category_sp
->IsEnabled())
378 lldb::ScriptedSyntheticChildrenSP
synth_current_sp(
379 (ScriptedSyntheticChildren
*)category_sp
->GetSyntheticForType(type_sp
)
381 if (synth_current_sp
&&
382 (synth_chosen_sp
.get() == nullptr ||
383 (prio_category
> category_sp
->GetEnabledPosition()))) {
384 prio_category
= category_sp
->GetEnabledPosition();
385 synth_chosen_sp
= synth_current_sp
;
388 return synth_chosen_sp
;
391 void FormatManager::ForEachCategory(TypeCategoryMap::ForEachCallback callback
) {
392 m_categories_map
.ForEach(callback
);
393 std::lock_guard
<std::recursive_mutex
> guard(m_language_categories_mutex
);
394 for (const auto &entry
: m_language_categories_map
) {
395 if (auto category_sp
= entry
.second
->GetCategory()) {
396 if (!callback(category_sp
))
402 lldb::TypeCategoryImplSP
403 FormatManager::GetCategory(ConstString category_name
, bool can_create
) {
405 return GetCategory(m_default_category_name
);
406 lldb::TypeCategoryImplSP category
;
407 if (m_categories_map
.Get(category_name
, category
))
411 return lldb::TypeCategoryImplSP();
413 m_categories_map
.Add(
415 lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name
)));
416 return GetCategory(category_name
);
419 lldb::Format
FormatManager::GetSingleItemFormat(lldb::Format vector_format
) {
420 switch (vector_format
) {
421 case eFormatVectorOfChar
:
422 return eFormatCharArray
;
424 case eFormatVectorOfSInt8
:
425 case eFormatVectorOfSInt16
:
426 case eFormatVectorOfSInt32
:
427 case eFormatVectorOfSInt64
:
428 return eFormatDecimal
;
430 case eFormatVectorOfUInt8
:
431 case eFormatVectorOfUInt16
:
432 case eFormatVectorOfUInt32
:
433 case eFormatVectorOfUInt64
:
434 case eFormatVectorOfUInt128
:
437 case eFormatVectorOfFloat16
:
438 case eFormatVectorOfFloat32
:
439 case eFormatVectorOfFloat64
:
443 return lldb::eFormatInvalid
;
447 bool FormatManager::ShouldPrintAsOneLiner(ValueObject
&valobj
) {
448 // if settings say no oneline whatsoever
449 if (valobj
.GetTargetSP().get() &&
450 !valobj
.GetTargetSP()->GetDebugger().GetAutoOneLineSummaries())
451 return false; // then don't oneline
453 // if this object has a summary, then ask the summary
454 if (valobj
.GetSummaryFormat().get() != nullptr)
455 return valobj
.GetSummaryFormat()->IsOneLiner();
457 // no children, no party
458 if (valobj
.GetNumChildren() == 0)
461 // ask the type if it has any opinion about this eLazyBoolCalculate == no
462 // opinion; other values should be self explanatory
463 CompilerType
compiler_type(valobj
.GetCompilerType());
464 if (compiler_type
.IsValid()) {
465 switch (compiler_type
.ShouldPrintAsOneLiner(&valobj
)) {
470 case eLazyBoolCalculate
:
475 size_t total_children_name_len
= 0;
477 for (size_t idx
= 0; idx
< valobj
.GetNumChildren(); idx
++) {
478 bool is_synth_val
= false;
479 ValueObjectSP
child_sp(valobj
.GetChildAtIndex(idx
));
480 // something is wrong here - bail out
484 // also ask the child's type if it has any opinion
485 CompilerType
child_compiler_type(child_sp
->GetCompilerType());
486 if (child_compiler_type
.IsValid()) {
487 switch (child_compiler_type
.ShouldPrintAsOneLiner(child_sp
.get())) {
489 // an opinion of yes is only binding for the child, so keep going
490 case eLazyBoolCalculate
:
493 // but if the child says no, then it's a veto on the whole thing
498 // if we decided to define synthetic children for a type, we probably care
499 // enough to show them, but avoid nesting children in children
500 if (child_sp
->GetSyntheticChildren().get() != nullptr) {
501 ValueObjectSP
synth_sp(child_sp
->GetSyntheticValue());
502 // wait.. wat? just get out of here..
505 // but if we only have them to provide a value, keep going
506 if (!synth_sp
->MightHaveChildren() &&
507 synth_sp
->DoesProvideSyntheticValue())
513 total_children_name_len
+= child_sp
->GetName().GetLength();
515 // 50 itself is a "randomly" chosen number - the idea is that
516 // overly long structs should not get this treatment
517 // FIXME: maybe make this a user-tweakable setting?
518 if (total_children_name_len
> 50)
521 // if a summary is there..
522 if (child_sp
->GetSummaryFormat()) {
523 // and it wants children, then bail out
524 if (child_sp
->GetSummaryFormat()->DoesPrintChildren(child_sp
.get()))
528 // if this child has children..
529 if (child_sp
->GetNumChildren()) {
530 // ...and no summary...
531 // (if it had a summary and the summary wanted children, we would have
533 // so this only makes us bail out if this has no summary and we would
534 // then print children)
535 if (!child_sp
->GetSummaryFormat() && !is_synth_val
) // but again only do
539 return false; // then bail out
545 ConstString
FormatManager::GetTypeForCache(ValueObject
&valobj
,
546 lldb::DynamicValueType use_dynamic
) {
547 ValueObjectSP valobj_sp
= valobj
.GetQualifiedRepresentationIfAvailable(
548 use_dynamic
, valobj
.IsSynthetic());
549 if (valobj_sp
&& valobj_sp
->GetCompilerType().IsValid()) {
550 if (!valobj_sp
->GetCompilerType().IsMeaninglessWithoutDynamicResolution())
551 return valobj_sp
->GetQualifiedTypeName();
553 return ConstString();
556 std::vector
<lldb::LanguageType
>
557 FormatManager::GetCandidateLanguages(lldb::LanguageType lang_type
) {
559 case lldb::eLanguageTypeC
:
560 case lldb::eLanguageTypeC89
:
561 case lldb::eLanguageTypeC99
:
562 case lldb::eLanguageTypeC11
:
563 case lldb::eLanguageTypeC_plus_plus
:
564 case lldb::eLanguageTypeC_plus_plus_03
:
565 case lldb::eLanguageTypeC_plus_plus_11
:
566 case lldb::eLanguageTypeC_plus_plus_14
:
567 return {lldb::eLanguageTypeC_plus_plus
, lldb::eLanguageTypeObjC
};
571 llvm_unreachable("Fully covered switch");
575 FormatManager::GetCategoryForLanguage(lldb::LanguageType lang_type
) {
576 std::lock_guard
<std::recursive_mutex
> guard(m_language_categories_mutex
);
577 auto iter
= m_language_categories_map
.find(lang_type
),
578 end
= m_language_categories_map
.end();
580 return iter
->second
.get();
581 LanguageCategory
*lang_category
= new LanguageCategory(lang_type
);
582 m_language_categories_map
[lang_type
] =
583 LanguageCategory::UniquePointer(lang_category
);
584 return lang_category
;
587 template <typename ImplSP
>
588 ImplSP
FormatManager::GetHardcoded(FormattersMatchData
&match_data
) {
590 for (lldb::LanguageType lang_type
: match_data
.GetCandidateLanguages()) {
591 if (LanguageCategory
*lang_category
= GetCategoryForLanguage(lang_type
)) {
592 if (lang_category
->GetHardcoded(*this, match_data
, retval_sp
))
600 template <typename ImplSP
> const char *FormatterKind
;
601 template <> const char *FormatterKind
<lldb::TypeFormatImplSP
> = "format";
602 template <> const char *FormatterKind
<lldb::TypeSummaryImplSP
> = "summary";
603 template <> const char *FormatterKind
<lldb::SyntheticChildrenSP
> = "synthetic";
606 #define FORMAT_LOG(Message) "[%s] " Message, FormatterKind<ImplSP>
608 template <typename ImplSP
>
609 ImplSP
FormatManager::Get(ValueObject
&valobj
,
610 lldb::DynamicValueType use_dynamic
) {
611 FormattersMatchData
match_data(valobj
, use_dynamic
);
612 if (ImplSP retval_sp
= GetCached
<ImplSP
>(match_data
))
615 Log
*log
= GetLog(LLDBLog::DataFormatters
);
617 LLDB_LOGF(log
, FORMAT_LOG("Search failed. Giving language a chance."));
618 for (lldb::LanguageType lang_type
: match_data
.GetCandidateLanguages()) {
619 if (LanguageCategory
*lang_category
= GetCategoryForLanguage(lang_type
)) {
621 if (lang_category
->Get(match_data
, retval_sp
))
623 LLDB_LOGF(log
, FORMAT_LOG("Language search success. Returning."));
629 LLDB_LOGF(log
, FORMAT_LOG("Search failed. Giving hardcoded a chance."));
630 return GetHardcoded
<ImplSP
>(match_data
);
633 template <typename ImplSP
>
634 ImplSP
FormatManager::GetCached(FormattersMatchData
&match_data
) {
636 Log
*log
= GetLog(LLDBLog::DataFormatters
);
637 if (match_data
.GetTypeForCache()) {
638 LLDB_LOGF(log
, "\n\n" FORMAT_LOG("Looking into cache for type %s"),
639 match_data
.GetTypeForCache().AsCString("<invalid>"));
640 if (m_format_cache
.Get(match_data
.GetTypeForCache(), retval_sp
)) {
642 LLDB_LOGF(log
, FORMAT_LOG("Cache search success. Returning."));
643 LLDB_LOGV(log
, "Cache hits: {0} - Cache Misses: {1}",
644 m_format_cache
.GetCacheHits(),
645 m_format_cache
.GetCacheMisses());
649 LLDB_LOGF(log
, FORMAT_LOG("Cache search failed. Going normal route"));
652 m_categories_map
.Get(match_data
, retval_sp
);
653 if (match_data
.GetTypeForCache() && (!retval_sp
|| !retval_sp
->NonCacheable())) {
654 LLDB_LOGF(log
, FORMAT_LOG("Caching %p for type %s"),
655 static_cast<void *>(retval_sp
.get()),
656 match_data
.GetTypeForCache().AsCString("<invalid>"));
657 m_format_cache
.Set(match_data
.GetTypeForCache(), retval_sp
);
659 LLDB_LOGV(log
, "Cache hits: {0} - Cache Misses: {1}",
660 m_format_cache
.GetCacheHits(), m_format_cache
.GetCacheMisses());
666 lldb::TypeFormatImplSP
667 FormatManager::GetFormat(ValueObject
&valobj
,
668 lldb::DynamicValueType use_dynamic
) {
669 return Get
<lldb::TypeFormatImplSP
>(valobj
, use_dynamic
);
672 lldb::TypeSummaryImplSP
673 FormatManager::GetSummaryFormat(ValueObject
&valobj
,
674 lldb::DynamicValueType use_dynamic
) {
675 return Get
<lldb::TypeSummaryImplSP
>(valobj
, use_dynamic
);
678 lldb::SyntheticChildrenSP
679 FormatManager::GetSyntheticChildren(ValueObject
&valobj
,
680 lldb::DynamicValueType use_dynamic
) {
681 return Get
<lldb::SyntheticChildrenSP
>(valobj
, use_dynamic
);
684 FormatManager::FormatManager()
685 : m_last_revision(0), m_format_cache(), m_language_categories_mutex(),
686 m_language_categories_map(), m_named_summaries_map(this),
687 m_categories_map(this), m_default_category_name(ConstString("default")),
688 m_system_category_name(ConstString("system")),
689 m_vectortypes_category_name(ConstString("VectorTypes")) {
690 LoadSystemFormatters();
691 LoadVectorFormatters();
693 EnableCategory(m_vectortypes_category_name
, TypeCategoryMap::Last
,
694 lldb::eLanguageTypeObjC_plus_plus
);
695 EnableCategory(m_system_category_name
, TypeCategoryMap::Last
,
696 lldb::eLanguageTypeObjC_plus_plus
);
699 void FormatManager::LoadSystemFormatters() {
700 TypeSummaryImpl::Flags string_flags
;
701 string_flags
.SetCascades(true)
702 .SetSkipPointers(true)
703 .SetSkipReferences(false)
704 .SetDontShowChildren(true)
705 .SetDontShowValue(false)
706 .SetShowMembersOneLiner(false)
707 .SetHideItemNames(false);
709 TypeSummaryImpl::Flags string_array_flags
;
710 string_array_flags
.SetCascades(true)
711 .SetSkipPointers(true)
712 .SetSkipReferences(false)
713 .SetDontShowChildren(true)
714 .SetDontShowValue(true)
715 .SetShowMembersOneLiner(false)
716 .SetHideItemNames(false);
718 lldb::TypeSummaryImplSP
string_format(
719 new StringSummaryFormat(string_flags
, "${var%s}"));
721 lldb::TypeSummaryImplSP
string_array_format(
722 new StringSummaryFormat(string_array_flags
, "${var%char[]}"));
724 TypeCategoryImpl::SharedPointer sys_category_sp
=
725 GetCategory(m_system_category_name
);
727 sys_category_sp
->AddTypeSummary(R
"(^(unsigned )?char ?(\*|\[\])$)",
728 eFormatterMatchRegex
, string_format
);
730 sys_category_sp
->AddTypeSummary(R
"(^((un)?signed )?char ?\[[0-9]+\]$)",
731 eFormatterMatchRegex
, string_array_format
);
733 lldb::TypeSummaryImplSP
ostype_summary(
734 new StringSummaryFormat(TypeSummaryImpl::Flags()
736 .SetSkipPointers(true)
737 .SetSkipReferences(true)
738 .SetDontShowChildren(true)
739 .SetDontShowValue(false)
740 .SetShowMembersOneLiner(false)
741 .SetHideItemNames(false),
744 sys_category_sp
->AddTypeSummary("OSType", eFormatterMatchExact
,
747 TypeFormatImpl::Flags fourchar_flags
;
748 fourchar_flags
.SetCascades(true).SetSkipPointers(true).SetSkipReferences(
751 AddFormat(sys_category_sp
, lldb::eFormatOSType
, "FourCharCode",
755 void FormatManager::LoadVectorFormatters() {
756 TypeCategoryImpl::SharedPointer vectors_category_sp
=
757 GetCategory(m_vectortypes_category_name
);
759 TypeSummaryImpl::Flags vector_flags
;
760 vector_flags
.SetCascades(true)
761 .SetSkipPointers(true)
762 .SetSkipReferences(false)
763 .SetDontShowChildren(true)
764 .SetDontShowValue(false)
765 .SetShowMembersOneLiner(true)
766 .SetHideItemNames(true);
768 AddStringSummary(vectors_category_sp
, "${var.uint128}", "builtin_type_vec128",
770 AddStringSummary(vectors_category_sp
, "", "float[4]", vector_flags
);
771 AddStringSummary(vectors_category_sp
, "", "int32_t[4]", vector_flags
);
772 AddStringSummary(vectors_category_sp
, "", "int16_t[8]", vector_flags
);
773 AddStringSummary(vectors_category_sp
, "", "vDouble", vector_flags
);
774 AddStringSummary(vectors_category_sp
, "", "vFloat", vector_flags
);
775 AddStringSummary(vectors_category_sp
, "", "vSInt8", vector_flags
);
776 AddStringSummary(vectors_category_sp
, "", "vSInt16", vector_flags
);
777 AddStringSummary(vectors_category_sp
, "", "vSInt32", vector_flags
);
778 AddStringSummary(vectors_category_sp
, "", "vUInt16", vector_flags
);
779 AddStringSummary(vectors_category_sp
, "", "vUInt8", vector_flags
);
780 AddStringSummary(vectors_category_sp
, "", "vUInt16", vector_flags
);
781 AddStringSummary(vectors_category_sp
, "", "vUInt32", vector_flags
);
782 AddStringSummary(vectors_category_sp
, "", "vBool32", vector_flags
);