1 //===-- CPlusPlusLanguage.cpp -----------------------------------*- C++ -*-===//
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 "CPlusPlusLanguage.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Demangle/ItaniumDemangle.h"
22 #include "lldb/Core/PluginManager.h"
23 #include "lldb/Core/UniqueCStringMap.h"
24 #include "lldb/DataFormatters/CXXFunctionPointer.h"
25 #include "lldb/DataFormatters/DataVisualization.h"
26 #include "lldb/DataFormatters/FormattersHelpers.h"
27 #include "lldb/DataFormatters/VectorType.h"
28 #include "lldb/Utility/ConstString.h"
29 #include "lldb/Utility/Log.h"
30 #include "lldb/Utility/RegularExpression.h"
32 #include "BlockPointer.h"
33 #include "CPlusPlusNameParser.h"
34 #include "CxxStringTypes.h"
36 #include "LibCxxAtomic.h"
37 #include "LibCxxVariant.h"
38 #include "LibStdcpp.h"
39 #include "MSVCUndecoratedNameParser.h"
42 using namespace lldb_private;
43 using namespace lldb_private::formatters;
45 void CPlusPlusLanguage::Initialize() {
46 PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
50 void CPlusPlusLanguage::Terminate() {
51 PluginManager::UnregisterPlugin(CreateInstance);
54 lldb_private::ConstString CPlusPlusLanguage::GetPluginNameStatic() {
55 static ConstString g_name("cplusplus");
59 // PluginInterface protocol
61 lldb_private::ConstString CPlusPlusLanguage::GetPluginName() {
62 return GetPluginNameStatic();
65 uint32_t CPlusPlusLanguage::GetPluginVersion() { return 1; }
69 Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) {
70 if (Language::LanguageIsCPlusPlus(language))
71 return new CPlusPlusLanguage();
75 void CPlusPlusLanguage::MethodName::Clear() {
77 m_basename = llvm::StringRef();
78 m_context = llvm::StringRef();
79 m_arguments = llvm::StringRef();
80 m_qualifiers = llvm::StringRef();
82 m_parse_error = false;
85 static bool ReverseFindMatchingChars(const llvm::StringRef &s,
86 const llvm::StringRef &left_right_chars,
87 size_t &left_pos, size_t &right_pos,
88 size_t pos = llvm::StringRef::npos) {
89 assert(left_right_chars.size() == 2);
90 left_pos = llvm::StringRef::npos;
91 const char left_char = left_right_chars[0];
92 const char right_char = left_right_chars[1];
93 pos = s.find_last_of(left_right_chars, pos);
94 if (pos == llvm::StringRef::npos || s[pos] == left_char)
98 while (pos > 0 && depth > 0) {
99 pos = s.find_last_of(left_right_chars, pos);
100 if (pos == llvm::StringRef::npos)
102 if (s[pos] == left_char) {
105 return left_pos < right_pos;
107 } else if (s[pos] == right_char) {
114 static bool IsTrivialBasename(const llvm::StringRef &basename) {
115 // Check that the basename matches with the following regular expression
116 // "^~?([A-Za-z_][A-Za-z_0-9]*)$" We are using a hand written implementation
117 // because it is significantly more efficient then using the general purpose
118 // regular expression library.
120 if (basename.size() > 0 && basename[0] == '~')
123 if (basename.size() <= idx)
124 return false; // Empty string or "~"
126 if (!std::isalpha(basename[idx]) && basename[idx] != '_')
127 return false; // First charater (after removing the possible '~'') isn't in
130 // Read all characters matching [A-Za-z_0-9]
132 while (idx < basename.size()) {
133 if (!std::isalnum(basename[idx]) && basename[idx] != '_')
138 // We processed all characters. It is a vaild basename.
139 return idx == basename.size();
142 bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
143 // This method tries to parse simple method definitions which are presumably
144 // most comman in user programs. Definitions that can be parsed by this
145 // function don't have return types and templates in the name.
146 // A::B::C::fun(std::vector<T> &) const
147 size_t arg_start, arg_end;
148 llvm::StringRef full(m_full.GetCString());
149 llvm::StringRef parens("()", 2);
150 if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
151 m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
152 if (arg_end + 1 < full.size())
153 m_qualifiers = full.substr(arg_end + 1).ltrim();
157 size_t basename_end = arg_start;
158 size_t context_start = 0;
159 size_t context_end = full.rfind(':', basename_end);
160 if (context_end == llvm::StringRef::npos)
161 m_basename = full.substr(0, basename_end);
163 if (context_start < context_end)
164 m_context = full.substr(context_start, context_end - 1 - context_start);
165 const size_t basename_begin = context_end + 1;
166 m_basename = full.substr(basename_begin, basename_end - basename_begin);
169 if (IsTrivialBasename(m_basename)) {
172 // The C++ basename doesn't match our regular expressions so this can't
173 // be a valid C++ method, clear everything out and indicate an error
174 m_context = llvm::StringRef();
175 m_basename = llvm::StringRef();
176 m_arguments = llvm::StringRef();
177 m_qualifiers = llvm::StringRef();
184 void CPlusPlusLanguage::MethodName::Parse() {
185 if (!m_parsed && m_full) {
186 if (TrySimplifiedParse()) {
187 m_parse_error = false;
189 CPlusPlusNameParser parser(m_full.GetStringRef());
190 if (auto function = parser.ParseAsFunctionDefinition()) {
191 m_basename = function.getValue().name.basename;
192 m_context = function.getValue().name.context;
193 m_arguments = function.getValue().arguments;
194 m_qualifiers = function.getValue().qualifiers;
195 m_parse_error = false;
197 m_parse_error = true;
204 llvm::StringRef CPlusPlusLanguage::MethodName::GetBasename() {
210 llvm::StringRef CPlusPlusLanguage::MethodName::GetContext() {
216 llvm::StringRef CPlusPlusLanguage::MethodName::GetArguments() {
222 llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
228 std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
231 if (m_context.empty())
241 bool CPlusPlusLanguage::IsCPPMangledName(const char *name) {
242 // FIXME!! we should really run through all the known C++ Language plugins
243 // and ask each one if this is a C++ mangled name
248 // MSVC style mangling
252 return (name[0] != '\0' && name[0] == '_' && name[1] == 'Z');
255 bool CPlusPlusLanguage::ExtractContextAndIdentifier(
256 const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
257 if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
258 return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
261 CPlusPlusNameParser parser(name);
262 if (auto full_name = parser.ParseAsFullName()) {
263 identifier = full_name.getValue().basename;
264 context = full_name.getValue().context;
271 class NodeAllocator {
272 llvm::BumpPtrAllocator Alloc;
275 void reset() { Alloc.Reset(); }
277 template <typename T, typename... Args> T *makeNode(Args &&... args) {
278 return new (Alloc.Allocate(sizeof(T), alignof(T)))
279 T(std::forward<Args>(args)...);
282 void *allocateNodeArray(size_t sz) {
283 return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
284 alignof(llvm::itanium_demangle::Node *));
288 /// Given a mangled function `Mangled`, replace all the primitive function type
289 /// arguments of `Search` with type `Replace`.
290 class TypeSubstitutor
291 : public llvm::itanium_demangle::AbstractManglingParser<TypeSubstitutor,
293 /// Input character until which we have constructed the respective output
297 llvm::StringRef Search;
298 llvm::StringRef Replace;
299 llvm::SmallString<128> Result;
301 /// Whether we have performed any substitutions.
304 void reset(llvm::StringRef Mangled, llvm::StringRef Search,
305 llvm::StringRef Replace) {
306 AbstractManglingParser::reset(Mangled.begin(), Mangled.end());
307 Written = Mangled.begin();
308 this->Search = Search;
309 this->Replace = Replace;
314 void appendUnchangedInput() {
315 Result += llvm::StringRef(Written, First - Written);
320 TypeSubstitutor() : AbstractManglingParser(nullptr, nullptr) {}
322 ConstString substitute(llvm::StringRef Mangled, llvm::StringRef From,
323 llvm::StringRef To) {
324 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
326 reset(Mangled, From, To);
327 if (parse() == nullptr) {
328 LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
329 return ConstString();
332 return ConstString();
334 // Append any trailing unmodified input.
335 appendUnchangedInput();
336 LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
337 return ConstString(Result);
340 llvm::itanium_demangle::Node *parseType() {
341 if (llvm::StringRef(First, numLeft()).startswith(Search)) {
342 // We found a match. Append unmodified input up to this point.
343 appendUnchangedInput();
345 // And then perform the replacement.
347 Written += Search.size();
350 return AbstractManglingParser::parseType();
355 uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings(
356 const ConstString mangled_name, std::set<ConstString> &alternates) {
357 const auto start_size = alternates.size();
358 /// Get a basic set of alternative manglings for the given symbol `name`, by
359 /// making a few basic possible substitutions on basic types, storage duration
360 /// and `const`ness for the given symbol. The output parameter `alternates`
361 /// is filled with a best-guess, non-exhaustive set of different manglings
362 /// for the given name.
364 // Maybe we're looking for a const symbol but the debug info told us it was
366 if (!strncmp(mangled_name.GetCString(), "_ZN", 3) &&
367 strncmp(mangled_name.GetCString(), "_ZNK", 4)) {
368 std::string fixed_scratch("_ZNK");
369 fixed_scratch.append(mangled_name.GetCString() + 3);
370 alternates.insert(ConstString(fixed_scratch));
373 // Maybe we're looking for a static symbol but we thought it was global...
374 if (!strncmp(mangled_name.GetCString(), "_Z", 2) &&
375 strncmp(mangled_name.GetCString(), "_ZL", 3)) {
376 std::string fixed_scratch("_ZL");
377 fixed_scratch.append(mangled_name.GetCString() + 2);
378 alternates.insert(ConstString(fixed_scratch));
382 // `char` is implementation defined as either `signed` or `unsigned`. As a
383 // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
384 // char, 'h'-unsigned char. If we're looking for symbols with a signed char
385 // parameter, try finding matches which have the general case 'c'.
386 if (ConstString char_fixup =
387 TS.substitute(mangled_name.GetStringRef(), "a", "c"))
388 alternates.insert(char_fixup);
390 // long long parameter mangling 'x', may actually just be a long 'l' argument
391 if (ConstString long_fixup =
392 TS.substitute(mangled_name.GetStringRef(), "x", "l"))
393 alternates.insert(long_fixup);
395 // unsigned long long parameter mangling 'y', may actually just be unsigned
397 if (ConstString ulong_fixup =
398 TS.substitute(mangled_name.GetStringRef(), "y", "m"))
399 alternates.insert(ulong_fixup);
401 return alternates.size() - start_size;
404 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
405 if (!cpp_category_sp)
408 TypeSummaryImpl::Flags stl_summary_flags;
409 stl_summary_flags.SetCascades(true)
410 .SetSkipPointers(false)
411 .SetSkipReferences(false)
412 .SetDontShowChildren(true)
413 .SetDontShowValue(true)
414 .SetShowMembersOneLiner(false)
415 .SetHideItemNames(false);
417 AddCXXSummary(cpp_category_sp,
418 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
419 "std::string summary provider",
420 ConstString("^std::__[[:alnum:]]+::string$"), stl_summary_flags,
422 AddCXXSummary(cpp_category_sp,
423 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
424 "std::string summary provider",
425 ConstString("^std::__[[:alnum:]]+::basic_string<char, "
426 "std::__[[:alnum:]]+::char_traits<char>, "
427 "std::__[[:alnum:]]+::allocator<char> >$"),
428 stl_summary_flags, true);
430 AddCXXSummary(cpp_category_sp,
431 lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
432 "std::u16string summary provider",
434 "^std::__[[:alnum:]]+::basic_string<char16_t, "
435 "std::__[[:alnum:]]+::char_traits<char16_t>, "
436 "std::__[[:alnum:]]+::allocator<char16_t> >$"),
437 stl_summary_flags, true);
439 AddCXXSummary(cpp_category_sp,
440 lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
441 "std::u32string summary provider",
443 "^std::__[[:alnum:]]+::basic_string<char32_t, "
444 "std::__[[:alnum:]]+::char_traits<char32_t>, "
445 "std::__[[:alnum:]]+::allocator<char32_t> >$"),
446 stl_summary_flags, true);
448 AddCXXSummary(cpp_category_sp,
449 lldb_private::formatters::LibcxxWStringSummaryProvider,
450 "std::wstring summary provider",
451 ConstString("^std::__[[:alnum:]]+::wstring$"),
452 stl_summary_flags, true);
453 AddCXXSummary(cpp_category_sp,
454 lldb_private::formatters::LibcxxWStringSummaryProvider,
455 "std::wstring summary provider",
456 ConstString("^std::__[[:alnum:]]+::basic_string<wchar_t, "
457 "std::__[[:alnum:]]+::char_traits<wchar_t>, "
458 "std::__[[:alnum:]]+::allocator<wchar_t> >$"),
459 stl_summary_flags, true);
461 SyntheticChildren::Flags stl_synth_flags;
462 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
464 SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
465 stl_deref_flags.SetFrontEndWantsDereference();
469 lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator,
470 "libc++ std::bitset synthetic children",
471 ConstString("^std::__[[:alnum:]]+::bitset<.+>(( )?&)?$"), stl_deref_flags,
475 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
476 "libc++ std::vector synthetic children",
477 ConstString("^std::__[[:alnum:]]+::vector<.+>(( )?&)?$"), stl_deref_flags,
481 lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
482 "libc++ std::forward_list synthetic children",
483 ConstString("^std::__[[:alnum:]]+::forward_list<.+>(( )?&)?$"),
484 stl_synth_flags, true);
487 lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator,
488 "libc++ std::list synthetic children",
489 // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>(( )?&)?$"
490 // so that it does not clash with: "^std::(__cxx11::)?list<.+>(( )?&)?$"
491 ConstString("^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
492 "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>(( )?&)?$"),
493 stl_deref_flags, true);
496 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
497 "libc++ std::map synthetic children",
498 ConstString("^std::__[[:alnum:]]+::map<.+> >(( )?&)?$"), stl_synth_flags,
502 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
503 "libc++ std::set synthetic children",
504 ConstString("^std::__[[:alnum:]]+::set<.+> >(( )?&)?$"), stl_deref_flags,
508 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
509 "libc++ std::multiset synthetic children",
510 ConstString("^std::__[[:alnum:]]+::multiset<.+> >(( )?&)?$"),
511 stl_deref_flags, true);
514 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
515 "libc++ std::multimap synthetic children",
516 ConstString("^std::__[[:alnum:]]+::multimap<.+> >(( )?&)?$"),
517 stl_synth_flags, true);
520 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator,
521 "libc++ std::unordered containers synthetic children",
522 ConstString("^(std::__[[:alnum:]]+::)unordered_(multi)?(map|set)<.+> >$"),
523 stl_synth_flags, true);
526 lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
527 "libc++ std::initializer_list synthetic children",
528 ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags,
530 AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator,
531 "libc++ std::queue synthetic children",
532 ConstString("^std::__[[:alnum:]]+::queue<.+>(( )?&)?$"),
533 stl_synth_flags, true);
534 AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator,
535 "libc++ std::tuple synthetic children",
536 ConstString("^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$"),
537 stl_synth_flags, true);
538 AddCXXSynthetic(cpp_category_sp, LibcxxOptionalFrontEndCreator,
539 "libc++ std::optional synthetic children",
540 ConstString("^std::__[[:alnum:]]+::optional<.+>(( )?&)?$"),
541 stl_synth_flags, true);
542 AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator,
543 "libc++ std::variant synthetic children",
544 ConstString("^std::__[[:alnum:]]+::variant<.+>(( )?&)?$"),
545 stl_synth_flags, true);
548 lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
549 "libc++ std::atomic synthetic children",
550 ConstString("^std::__[[:alnum:]]+::atomic<.+>$"), stl_synth_flags, true);
552 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
554 llvm::StringRef("^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$")),
555 SyntheticChildrenSP(new ScriptedSyntheticChildren(
557 "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
561 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
562 "shared_ptr synthetic children",
563 ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"),
564 stl_synth_flags, true);
567 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
568 "weak_ptr synthetic children",
569 ConstString("^(std::__[[:alnum:]]+::)weak_ptr<.+>(( )?&)?$"),
570 stl_synth_flags, true);
572 stl_summary_flags.SetDontShowChildren(false);
573 stl_summary_flags.SetSkipPointers(false);
574 AddCXXSummary(cpp_category_sp,
575 lldb_private::formatters::LibcxxContainerSummaryProvider,
576 "libc++ std::bitset summary provider",
577 ConstString("^std::__[[:alnum:]]+::bitset<.+>(( )?&)?$"),
578 stl_summary_flags, true);
579 AddCXXSummary(cpp_category_sp,
580 lldb_private::formatters::LibcxxContainerSummaryProvider,
581 "libc++ std::vector summary provider",
582 ConstString("^std::__[[:alnum:]]+::vector<.+>(( )?&)?$"),
583 stl_summary_flags, true);
584 AddCXXSummary(cpp_category_sp,
585 lldb_private::formatters::LibcxxContainerSummaryProvider,
586 "libc++ std::list summary provider",
587 ConstString("^std::__[[:alnum:]]+::forward_list<.+>(( )?&)?$"),
588 stl_summary_flags, true);
590 cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
591 "libc++ std::list summary provider",
592 // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>(( )?&)?$"
593 // so that it does not clash with: "^std::(__cxx11::)?list<.+>(( )?&)?$"
594 ConstString("^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
595 "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>(( )?&)?$"),
596 stl_summary_flags, true);
597 AddCXXSummary(cpp_category_sp,
598 lldb_private::formatters::LibcxxContainerSummaryProvider,
599 "libc++ std::map summary provider",
600 ConstString("^std::__[[:alnum:]]+::map<.+>(( )?&)?$"),
601 stl_summary_flags, true);
602 AddCXXSummary(cpp_category_sp,
603 lldb_private::formatters::LibcxxContainerSummaryProvider,
604 "libc++ std::deque summary provider",
605 ConstString("^std::__[[:alnum:]]+::deque<.+>(( )?&)?$"),
606 stl_summary_flags, true);
607 AddCXXSummary(cpp_category_sp,
608 lldb_private::formatters::LibcxxContainerSummaryProvider,
609 "libc++ std::queue summary provider",
610 ConstString("^std::__[[:alnum:]]+::queue<.+>(( )?&)?$"),
611 stl_summary_flags, true);
612 AddCXXSummary(cpp_category_sp,
613 lldb_private::formatters::LibcxxContainerSummaryProvider,
614 "libc++ std::set summary provider",
615 ConstString("^std::__[[:alnum:]]+::set<.+>(( )?&)?$"),
616 stl_summary_flags, true);
617 AddCXXSummary(cpp_category_sp,
618 lldb_private::formatters::LibcxxContainerSummaryProvider,
619 "libc++ std::multiset summary provider",
620 ConstString("^std::__[[:alnum:]]+::multiset<.+>(( )?&)?$"),
621 stl_summary_flags, true);
622 AddCXXSummary(cpp_category_sp,
623 lldb_private::formatters::LibcxxContainerSummaryProvider,
624 "libc++ std::multimap summary provider",
625 ConstString("^std::__[[:alnum:]]+::multimap<.+>(( )?&)?$"),
626 stl_summary_flags, true);
628 cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
629 "libc++ std::unordered containers summary provider",
630 ConstString("^(std::__[[:alnum:]]+::)unordered_(multi)?(map|set)<.+> >$"),
631 stl_summary_flags, true);
632 AddCXXSummary(cpp_category_sp, LibcxxContainerSummaryProvider,
633 "libc++ std::tuple summary provider",
634 ConstString("^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$"),
635 stl_summary_flags, true);
637 cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider,
638 "libc++ std::atomic summary provider",
639 ConstString("^std::__[[:alnum:]]+::atomic<.+>$"), stl_summary_flags,
641 AddCXXSummary(cpp_category_sp,
642 lldb_private::formatters::LibcxxOptionalSummaryProvider,
643 "libc++ std::optional summary provider",
644 ConstString("^std::__[[:alnum:]]+::optional<.+>(( )?&)?$"),
645 stl_summary_flags, true);
646 AddCXXSummary(cpp_category_sp,
647 lldb_private::formatters::LibcxxVariantSummaryProvider,
648 "libc++ std::variant summary provider",
649 ConstString("^std::__[[:alnum:]]+::variant<.+>(( )?&)?$"),
650 stl_summary_flags, true);
652 stl_summary_flags.SetSkipPointers(true);
654 AddCXXSummary(cpp_category_sp,
655 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
656 "libc++ std::shared_ptr summary provider",
657 ConstString("^std::__[[:alnum:]]+::shared_ptr<.+>(( )?&)?$"),
658 stl_summary_flags, true);
659 AddCXXSummary(cpp_category_sp,
660 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
661 "libc++ std::weak_ptr summary provider",
662 ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"),
663 stl_summary_flags, true);
667 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator,
668 "std::vector iterator synthetic children",
669 ConstString("^std::__[[:alnum:]]+::__wrap_iter<.+>$"), stl_synth_flags,
674 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
675 "std::map iterator synthetic children",
676 ConstString("^std::__[[:alnum:]]+::__map_iterator<.+>$"), stl_synth_flags,
680 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
681 if (!cpp_category_sp)
684 TypeSummaryImpl::Flags stl_summary_flags;
685 stl_summary_flags.SetCascades(true)
686 .SetSkipPointers(false)
687 .SetSkipReferences(false)
688 .SetDontShowChildren(true)
689 .SetDontShowValue(true)
690 .SetShowMembersOneLiner(false)
691 .SetHideItemNames(false);
693 lldb::TypeSummaryImplSP std_string_summary_sp(
694 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}"));
696 lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(
697 stl_summary_flags, LibStdcppStringSummaryProvider,
698 "libstdc++ c++11 std::string summary provider"));
699 lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(
700 stl_summary_flags, LibStdcppWStringSummaryProvider,
701 "libstdc++ c++11 std::wstring summary provider"));
703 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
704 std_string_summary_sp);
705 cpp_category_sp->GetTypeSummariesContainer()->Add(
706 ConstString("std::basic_string<char>"), std_string_summary_sp);
707 cpp_category_sp->GetTypeSummariesContainer()->Add(
708 ConstString("std::basic_string<char,std::char_traits<char>,std::"
709 "allocator<char> >"),
710 std_string_summary_sp);
711 cpp_category_sp->GetTypeSummariesContainer()->Add(
712 ConstString("std::basic_string<char, std::char_traits<char>, "
713 "std::allocator<char> >"),
714 std_string_summary_sp);
716 cpp_category_sp->GetTypeSummariesContainer()->Add(
717 ConstString("std::__cxx11::string"), cxx11_string_summary_sp);
718 cpp_category_sp->GetTypeSummariesContainer()->Add(
719 ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, "
720 "std::allocator<char> >"),
721 cxx11_string_summary_sp);
723 // making sure we force-pick the summary for printing wstring (_M_p is a
725 lldb::TypeSummaryImplSP std_wstring_summary_sp(
726 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
728 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"),
729 std_wstring_summary_sp);
730 cpp_category_sp->GetTypeSummariesContainer()->Add(
731 ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp);
732 cpp_category_sp->GetTypeSummariesContainer()->Add(
733 ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::"
734 "allocator<wchar_t> >"),
735 std_wstring_summary_sp);
736 cpp_category_sp->GetTypeSummariesContainer()->Add(
737 ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, "
738 "std::allocator<wchar_t> >"),
739 std_wstring_summary_sp);
741 cpp_category_sp->GetTypeSummariesContainer()->Add(
742 ConstString("std::__cxx11::wstring"), cxx11_wstring_summary_sp);
743 cpp_category_sp->GetTypeSummariesContainer()->Add(
744 ConstString("std::__cxx11::basic_string<wchar_t, "
745 "std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
746 cxx11_wstring_summary_sp);
748 SyntheticChildren::Flags stl_synth_flags;
749 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
752 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
753 RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$")),
754 SyntheticChildrenSP(new ScriptedSyntheticChildren(
756 "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
757 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
758 RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$")),
759 SyntheticChildrenSP(new ScriptedSyntheticChildren(
761 "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider")));
762 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
763 RegularExpression(llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$")),
764 SyntheticChildrenSP(new ScriptedSyntheticChildren(
766 "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
767 stl_summary_flags.SetDontShowChildren(false);
768 stl_summary_flags.SetSkipPointers(true);
769 cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
770 RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$")),
772 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
773 cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
774 RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$")),
776 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
777 cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
778 RegularExpression(llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$")),
780 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
784 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator,
785 "std::vector iterator synthetic children",
786 ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
790 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator,
791 "std::map iterator synthetic children",
792 ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
796 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
797 "std::unique_ptr synthetic children",
798 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
801 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
802 "std::shared_ptr synthetic children",
803 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
806 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
807 "std::weak_ptr synthetic children",
808 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
811 lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
812 "std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"),
813 stl_synth_flags, true);
815 AddCXXSummary(cpp_category_sp,
816 lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
817 "libstdc++ std::unique_ptr summary provider",
818 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_summary_flags,
820 AddCXXSummary(cpp_category_sp,
821 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
822 "libstdc++ std::shared_ptr summary provider",
823 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags,
825 AddCXXSummary(cpp_category_sp,
826 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
827 "libstdc++ std::weak_ptr summary provider",
828 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags,
832 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
833 if (!cpp_category_sp)
836 TypeSummaryImpl::Flags string_flags;
837 string_flags.SetCascades(true)
838 .SetSkipPointers(true)
839 .SetSkipReferences(false)
840 .SetDontShowChildren(true)
841 .SetDontShowValue(false)
842 .SetShowMembersOneLiner(false)
843 .SetHideItemNames(false);
845 TypeSummaryImpl::Flags string_array_flags;
846 string_array_flags.SetCascades(true)
847 .SetSkipPointers(true)
848 .SetSkipReferences(false)
849 .SetDontShowChildren(true)
850 .SetDontShowValue(true)
851 .SetShowMembersOneLiner(false)
852 .SetHideItemNames(false);
854 // FIXME because of a bug in the FormattersContainer we need to add a summary
855 // for both X* and const X* (<rdar://problem/12717717>)
857 cpp_category_sp, lldb_private::formatters::Char8StringSummaryProvider,
858 "char8_t * summary provider", ConstString("char8_t *"), string_flags);
859 AddCXXSummary(cpp_category_sp,
860 lldb_private::formatters::Char8StringSummaryProvider,
861 "char8_t [] summary provider",
862 ConstString("char8_t \\[[0-9]+\\]"), string_array_flags, true);
865 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
866 "char16_t * summary provider", ConstString("char16_t *"), string_flags);
867 AddCXXSummary(cpp_category_sp,
868 lldb_private::formatters::Char16StringSummaryProvider,
869 "char16_t [] summary provider",
870 ConstString("char16_t \\[[0-9]+\\]"), string_array_flags, true);
873 cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider,
874 "char32_t * summary provider", ConstString("char32_t *"), string_flags);
875 AddCXXSummary(cpp_category_sp,
876 lldb_private::formatters::Char32StringSummaryProvider,
877 "char32_t [] summary provider",
878 ConstString("char32_t \\[[0-9]+\\]"), string_array_flags, true);
881 cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider,
882 "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
883 AddCXXSummary(cpp_category_sp,
884 lldb_private::formatters::WCharStringSummaryProvider,
885 "wchar_t * summary provider",
886 ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true);
889 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
890 "unichar * summary provider", ConstString("unichar *"), string_flags);
892 TypeSummaryImpl::Flags widechar_flags;
893 widechar_flags.SetDontShowValue(true)
894 .SetSkipPointers(true)
895 .SetSkipReferences(false)
897 .SetDontShowChildren(true)
898 .SetHideItemNames(true)
899 .SetShowMembersOneLiner(false);
901 AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char8SummaryProvider,
902 "char8_t summary provider", ConstString("char8_t"),
905 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
906 "char16_t summary provider", ConstString("char16_t"), widechar_flags);
908 cpp_category_sp, lldb_private::formatters::Char32SummaryProvider,
909 "char32_t summary provider", ConstString("char32_t"), widechar_flags);
910 AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider,
911 "wchar_t summary provider", ConstString("wchar_t"),
915 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
916 "unichar summary provider", ConstString("unichar"), widechar_flags);
919 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() {
920 class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger {
922 CompilerType AdjustForInclusion(CompilerType &candidate) override {
923 LanguageType lang_type(candidate.GetMinimumLanguage());
924 if (!Language::LanguageIsC(lang_type) &&
925 !Language::LanguageIsCPlusPlus(lang_type))
926 return CompilerType();
927 if (candidate.IsTypedefType())
928 return candidate.GetTypedefedType();
933 return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
936 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
937 static llvm::once_flag g_initialize;
938 static TypeCategoryImplSP g_category;
940 llvm::call_once(g_initialize, [this]() -> void {
941 DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
943 LoadLibStdcppFormatters(g_category);
944 LoadLibCxxFormatters(g_category);
945 LoadSystemFormatters(g_category);
951 HardcodedFormatters::HardcodedSummaryFinder
952 CPlusPlusLanguage::GetHardcodedSummaries() {
953 static llvm::once_flag g_initialize;
954 static ConstString g_vectortypes("VectorTypes");
955 static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
957 llvm::call_once(g_initialize, []() -> void {
958 g_formatters.push_back(
959 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
960 FormatManager &) -> TypeSummaryImpl::SharedPointer {
961 static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
962 new CXXFunctionSummaryFormat(
963 TypeSummaryImpl::Flags(),
964 lldb_private::formatters::CXXFunctionPointerSummaryProvider,
965 "Function pointer summary provider"));
966 if (valobj.GetCompilerType().IsFunctionPointerType()) {
971 g_formatters.push_back(
972 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
973 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
974 static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
975 new CXXFunctionSummaryFormat(
976 TypeSummaryImpl::Flags()
978 .SetDontShowChildren(true)
979 .SetHideItemNames(true)
980 .SetShowMembersOneLiner(true)
981 .SetSkipPointers(true)
982 .SetSkipReferences(false),
983 lldb_private::formatters::VectorTypeSummaryProvider,
984 "vector_type pointer summary provider"));
985 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) {
986 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
991 g_formatters.push_back(
992 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
993 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
994 static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
995 new CXXFunctionSummaryFormat(
996 TypeSummaryImpl::Flags()
998 .SetDontShowChildren(true)
999 .SetHideItemNames(true)
1000 .SetShowMembersOneLiner(true)
1001 .SetSkipPointers(true)
1002 .SetSkipReferences(false),
1003 lldb_private::formatters::BlockPointerSummaryProvider,
1004 "block pointer summary provider"));
1005 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) {
1006 return formatter_sp;
1012 return g_formatters;
1015 HardcodedFormatters::HardcodedSyntheticFinder
1016 CPlusPlusLanguage::GetHardcodedSynthetics() {
1017 static llvm::once_flag g_initialize;
1018 static ConstString g_vectortypes("VectorTypes");
1019 static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
1021 llvm::call_once(g_initialize, []() -> void {
1022 g_formatters.push_back([](lldb_private::ValueObject &valobj,
1023 lldb::DynamicValueType,
1025 fmt_mgr) -> SyntheticChildren::SharedPointer {
1026 static CXXSyntheticChildren::SharedPointer formatter_sp(
1027 new CXXSyntheticChildren(
1028 SyntheticChildren::Flags()
1030 .SetSkipPointers(true)
1031 .SetSkipReferences(true)
1032 .SetNonCacheable(true),
1033 "vector_type synthetic children",
1034 lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
1035 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) {
1036 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1037 return formatter_sp;
1041 g_formatters.push_back([](lldb_private::ValueObject &valobj,
1042 lldb::DynamicValueType,
1044 fmt_mgr) -> SyntheticChildren::SharedPointer {
1045 static CXXSyntheticChildren::SharedPointer formatter_sp(
1046 new CXXSyntheticChildren(
1047 SyntheticChildren::Flags()
1049 .SetSkipPointers(true)
1050 .SetSkipReferences(true)
1051 .SetNonCacheable(true),
1052 "block pointer synthetic children",
1053 lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
1054 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) {
1055 return formatter_sp;
1062 return g_formatters;
1065 bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
1066 const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c",
1067 ".h", ".hh", ".hpp", ".hxx", ".h++"};
1068 for (auto suffix : suffixes) {
1069 if (file_path.endswith_lower(suffix))
1073 // Check if we're in a STL path (where the files usually have no extension
1074 // that we could check for.
1075 return file_path.contains("/usr/include/c++/");