1 //===-- CPlusPlusLanguage.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 "CPlusPlusLanguage.h"
10 
11 #include <cctype>
12 #include <cstring>
13 
14 #include <functional>
15 #include <memory>
16 #include <mutex>
17 #include <set>
18 
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Demangle/ItaniumDemangle.h"
21 
22 #include "lldb/Core/Mangled.h"
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/PluginManager.h"
25 #include "lldb/Core/UniqueCStringMap.h"
26 #include "lldb/DataFormatters/CXXFunctionPointer.h"
27 #include "lldb/DataFormatters/DataVisualization.h"
28 #include "lldb/DataFormatters/FormattersHelpers.h"
29 #include "lldb/DataFormatters/VectorType.h"
30 #include "lldb/Symbol/SymbolFile.h"
31 #include "lldb/Utility/ConstString.h"
32 #include "lldb/Utility/LLDBLog.h"
33 #include "lldb/Utility/Log.h"
34 #include "lldb/Utility/RegularExpression.h"
35 
36 #include "BlockPointer.h"
37 #include "CPlusPlusNameParser.h"
38 #include "CxxStringTypes.h"
39 #include "Generic.h"
40 #include "LibCxx.h"
41 #include "LibCxxAtomic.h"
42 #include "LibCxxVariant.h"
43 #include "LibStdcpp.h"
44 #include "MSVCUndecoratedNameParser.h"
45 
46 using namespace lldb;
47 using namespace lldb_private;
48 using namespace lldb_private::formatters;
49 
50 LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)
51 
52 void CPlusPlusLanguage::Initialize() {
53   PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
54                                 CreateInstance);
55 }
56 
57 void CPlusPlusLanguage::Terminate() {
58   PluginManager::UnregisterPlugin(CreateInstance);
59 }
60 
61 bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
62   const char *mangled_name = mangled.GetMangledName().GetCString();
63   return mangled_name && CPlusPlusLanguage::IsCPPMangledName(mangled_name);
64 }
65 
66 ConstString CPlusPlusLanguage::GetDemangledFunctionNameWithoutArguments(
67     Mangled mangled) const {
68   const char *mangled_name_cstr = mangled.GetMangledName().GetCString();
69   ConstString demangled_name = mangled.GetDemangledName();
70   if (demangled_name && mangled_name_cstr && mangled_name_cstr[0]) {
71     if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
72         (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure,
73                                         // typeinfo structure, and typeinfo
74                                         // mangled_name
75          mangled_name_cstr[2] != 'G' && // avoid guard variables
76          mangled_name_cstr[2] != 'Z'))  // named local entities (if we
77                                         // eventually handle eSymbolTypeData,
78                                         // we will want this back)
79     {
80       CPlusPlusLanguage::MethodName cxx_method(demangled_name);
81       if (!cxx_method.GetBasename().empty()) {
82         std::string shortname;
83         if (!cxx_method.GetContext().empty())
84           shortname = cxx_method.GetContext().str() + "::";
85         shortname += cxx_method.GetBasename().str();
86         return ConstString(shortname);
87       }
88     }
89   }
90   if (demangled_name)
91     return demangled_name;
92   return mangled.GetMangledName();
93 }
94 
95 // Static Functions
96 
97 Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) {
98   // Use plugin for C++ but not for Objective-C++ (which has its own plugin).
99   if (Language::LanguageIsCPlusPlus(language) &&
100       language != eLanguageTypeObjC_plus_plus)
101     return new CPlusPlusLanguage();
102   return nullptr;
103 }
104 
105 void CPlusPlusLanguage::MethodName::Clear() {
106   m_full.Clear();
107   m_basename = llvm::StringRef();
108   m_context = llvm::StringRef();
109   m_arguments = llvm::StringRef();
110   m_qualifiers = llvm::StringRef();
111   m_parsed = false;
112   m_parse_error = false;
113 }
114 
115 static bool ReverseFindMatchingChars(const llvm::StringRef &s,
116                                      const llvm::StringRef &left_right_chars,
117                                      size_t &left_pos, size_t &right_pos,
118                                      size_t pos = llvm::StringRef::npos) {
119   assert(left_right_chars.size() == 2);
120   left_pos = llvm::StringRef::npos;
121   const char left_char = left_right_chars[0];
122   const char right_char = left_right_chars[1];
123   pos = s.find_last_of(left_right_chars, pos);
124   if (pos == llvm::StringRef::npos || s[pos] == left_char)
125     return false;
126   right_pos = pos;
127   uint32_t depth = 1;
128   while (pos > 0 && depth > 0) {
129     pos = s.find_last_of(left_right_chars, pos);
130     if (pos == llvm::StringRef::npos)
131       return false;
132     if (s[pos] == left_char) {
133       if (--depth == 0) {
134         left_pos = pos;
135         return left_pos < right_pos;
136       }
137     } else if (s[pos] == right_char) {
138       ++depth;
139     }
140   }
141   return false;
142 }
143 
144 static bool IsTrivialBasename(const llvm::StringRef &basename) {
145   // Check that the basename matches with the following regular expression
146   // "^~?([A-Za-z_][A-Za-z_0-9]*)$" We are using a hand written implementation
147   // because it is significantly more efficient then using the general purpose
148   // regular expression library.
149   size_t idx = 0;
150   if (basename.size() > 0 && basename[0] == '~')
151     idx = 1;
152 
153   if (basename.size() <= idx)
154     return false; // Empty string or "~"
155 
156   if (!std::isalpha(basename[idx]) && basename[idx] != '_')
157     return false; // First character (after removing the possible '~'') isn't in
158                   // [A-Za-z_]
159 
160   // Read all characters matching [A-Za-z_0-9]
161   ++idx;
162   while (idx < basename.size()) {
163     if (!std::isalnum(basename[idx]) && basename[idx] != '_')
164       break;
165     ++idx;
166   }
167 
168   // We processed all characters. It is a vaild basename.
169   return idx == basename.size();
170 }
171 
172 bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
173   // This method tries to parse simple method definitions which are presumably
174   // most comman in user programs. Definitions that can be parsed by this
175   // function don't have return types and templates in the name.
176   // A::B::C::fun(std::vector<T> &) const
177   size_t arg_start, arg_end;
178   llvm::StringRef full(m_full.GetCString());
179   llvm::StringRef parens("()", 2);
180   if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
181     m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
182     if (arg_end + 1 < full.size())
183       m_qualifiers = full.substr(arg_end + 1).ltrim();
184 
185     if (arg_start == 0)
186       return false;
187     size_t basename_end = arg_start;
188     size_t context_start = 0;
189     size_t context_end = full.rfind(':', basename_end);
190     if (context_end == llvm::StringRef::npos)
191       m_basename = full.substr(0, basename_end);
192     else {
193       if (context_start < context_end)
194         m_context = full.substr(context_start, context_end - 1 - context_start);
195       const size_t basename_begin = context_end + 1;
196       m_basename = full.substr(basename_begin, basename_end - basename_begin);
197     }
198 
199     if (IsTrivialBasename(m_basename)) {
200       return true;
201     } else {
202       // The C++ basename doesn't match our regular expressions so this can't
203       // be a valid C++ method, clear everything out and indicate an error
204       m_context = llvm::StringRef();
205       m_basename = llvm::StringRef();
206       m_arguments = llvm::StringRef();
207       m_qualifiers = llvm::StringRef();
208       return false;
209     }
210   }
211   return false;
212 }
213 
214 void CPlusPlusLanguage::MethodName::Parse() {
215   if (!m_parsed && m_full) {
216     if (TrySimplifiedParse()) {
217       m_parse_error = false;
218     } else {
219       CPlusPlusNameParser parser(m_full.GetStringRef());
220       if (auto function = parser.ParseAsFunctionDefinition()) {
221         m_basename = function.value().name.basename;
222         m_context = function.value().name.context;
223         m_arguments = function.value().arguments;
224         m_qualifiers = function.value().qualifiers;
225         m_parse_error = false;
226       } else {
227         m_parse_error = true;
228       }
229     }
230     m_parsed = true;
231   }
232 }
233 
234 llvm::StringRef CPlusPlusLanguage::MethodName::GetBasename() {
235   if (!m_parsed)
236     Parse();
237   return m_basename;
238 }
239 
240 llvm::StringRef CPlusPlusLanguage::MethodName::GetContext() {
241   if (!m_parsed)
242     Parse();
243   return m_context;
244 }
245 
246 llvm::StringRef CPlusPlusLanguage::MethodName::GetArguments() {
247   if (!m_parsed)
248     Parse();
249   return m_arguments;
250 }
251 
252 llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
253   if (!m_parsed)
254     Parse();
255   return m_qualifiers;
256 }
257 
258 std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
259   if (!m_parsed)
260     Parse();
261   if (m_context.empty())
262     return std::string(m_basename);
263 
264   std::string res;
265   res += m_context;
266   res += "::";
267   res += m_basename;
268   return res;
269 }
270 
271 bool CPlusPlusLanguage::MethodName::ContainsPath(llvm::StringRef path) {
272   if (!m_parsed)
273     Parse();
274   // If we can't parse the incoming name, then just check that it contains path.
275   if (m_parse_error)
276     return m_full.GetStringRef().contains(path);
277 
278   llvm::StringRef identifier;
279   llvm::StringRef context;
280   std::string path_str = path.str();
281   bool success
282       = CPlusPlusLanguage::ExtractContextAndIdentifier(path_str.c_str(),
283                                                        context,
284                                                        identifier);
285   if (!success)
286     return m_full.GetStringRef().contains(path);
287 
288   if (identifier != GetBasename())
289     return false;
290   // Incoming path only had an identifier, so we match.
291   if (context.empty())
292     return true;
293   // Incoming path has context but this method does not, no match.
294   if (m_context.empty())
295     return false;
296 
297   llvm::StringRef haystack = m_context;
298   if (!haystack.consume_back(context))
299     return false;
300   if (haystack.empty() || !isalnum(haystack.back()))
301     return true;
302 
303   return false;
304 }
305 
306 bool CPlusPlusLanguage::IsCPPMangledName(llvm::StringRef name) {
307   // FIXME!! we should really run through all the known C++ Language plugins
308   // and ask each one if this is a C++ mangled name
309 
310   Mangled::ManglingScheme scheme = Mangled::GetManglingScheme(name);
311 
312   if (scheme == Mangled::eManglingSchemeNone)
313     return false;
314 
315   return true;
316 }
317 
318 bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path,
319                                                   ConstString demangled) const {
320   MethodName demangled_name(demangled);
321   return demangled_name.ContainsPath(path);
322 }
323 
324 bool CPlusPlusLanguage::ExtractContextAndIdentifier(
325     const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
326   if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
327     return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
328                                                                   identifier);
329 
330   CPlusPlusNameParser parser(name);
331   if (auto full_name = parser.ParseAsFullName()) {
332     identifier = full_name.value().basename;
333     context = full_name.value().context;
334     return true;
335   }
336   return false;
337 }
338 
339 namespace {
340 class NodeAllocator {
341   llvm::BumpPtrAllocator Alloc;
342 
343 public:
344   void reset() { Alloc.Reset(); }
345 
346   template <typename T, typename... Args> T *makeNode(Args &&... args) {
347     return new (Alloc.Allocate(sizeof(T), alignof(T)))
348         T(std::forward<Args>(args)...);
349   }
350 
351   void *allocateNodeArray(size_t sz) {
352     return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
353                           alignof(llvm::itanium_demangle::Node *));
354   }
355 };
356 
357 template <typename Derived>
358 class ManglingSubstitutor
359     : public llvm::itanium_demangle::AbstractManglingParser<Derived,
360                                                             NodeAllocator> {
361   using Base =
362       llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
363 
364 public:
365   ManglingSubstitutor() : Base(nullptr, nullptr) {}
366 
367   template <typename... Ts>
368   ConstString substitute(llvm::StringRef Mangled, Ts &&... Vals) {
369     this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
370     return substituteImpl(Mangled);
371   }
372 
373 protected:
374   void reset(llvm::StringRef Mangled) {
375     Base::reset(Mangled.begin(), Mangled.end());
376     Written = Mangled.begin();
377     Result.clear();
378     Substituted = false;
379   }
380 
381   ConstString substituteImpl(llvm::StringRef Mangled) {
382     Log *log = GetLog(LLDBLog::Language);
383     if (this->parse() == nullptr) {
384       LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
385       return ConstString();
386     }
387     if (!Substituted)
388       return ConstString();
389 
390     // Append any trailing unmodified input.
391     appendUnchangedInput();
392     LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
393     return ConstString(Result);
394   }
395 
396   void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
397     if (!llvm::StringRef(currentParserPos(), this->numLeft()).startswith(From))
398       return;
399 
400     // We found a match. Append unmodified input up to this point.
401     appendUnchangedInput();
402 
403     // And then perform the replacement.
404     Result += To;
405     Written += From.size();
406     Substituted = true;
407   }
408 
409 private:
410   /// Input character until which we have constructed the respective output
411   /// already.
412   const char *Written = "";
413 
414   llvm::SmallString<128> Result;
415 
416   /// Whether we have performed any substitutions.
417   bool Substituted = false;
418 
419   const char *currentParserPos() const { return this->First; }
420 
421   void appendUnchangedInput() {
422     Result +=
423         llvm::StringRef(Written, std::distance(Written, currentParserPos()));
424     Written = currentParserPos();
425   }
426 };
427 
428 /// Given a mangled function `Mangled`, replace all the primitive function type
429 /// arguments of `Search` with type `Replace`.
430 class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
431   llvm::StringRef Search;
432   llvm::StringRef Replace;
433 
434 public:
435   void reset(llvm::StringRef Mangled, llvm::StringRef Search,
436              llvm::StringRef Replace) {
437     ManglingSubstitutor::reset(Mangled);
438     this->Search = Search;
439     this->Replace = Replace;
440   }
441 
442   llvm::itanium_demangle::Node *parseType() {
443     trySubstitute(Search, Replace);
444     return ManglingSubstitutor::parseType();
445   }
446 };
447 
448 class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
449 public:
450   llvm::itanium_demangle::Node *
451   parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
452     trySubstitute("C1", "C2");
453     trySubstitute("D1", "D2");
454     return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
455   }
456 };
457 } // namespace
458 
459 std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
460     const ConstString mangled_name) const {
461   std::vector<ConstString> alternates;
462 
463   /// Get a basic set of alternative manglings for the given symbol `name`, by
464   /// making a few basic possible substitutions on basic types, storage duration
465   /// and `const`ness for the given symbol. The output parameter `alternates`
466   /// is filled with a best-guess, non-exhaustive set of different manglings
467   /// for the given name.
468 
469   // Maybe we're looking for a const symbol but the debug info told us it was
470   // non-const...
471   if (!strncmp(mangled_name.GetCString(), "_ZN", 3) &&
472       strncmp(mangled_name.GetCString(), "_ZNK", 4)) {
473     std::string fixed_scratch("_ZNK");
474     fixed_scratch.append(mangled_name.GetCString() + 3);
475     alternates.push_back(ConstString(fixed_scratch));
476   }
477 
478   // Maybe we're looking for a static symbol but we thought it was global...
479   if (!strncmp(mangled_name.GetCString(), "_Z", 2) &&
480       strncmp(mangled_name.GetCString(), "_ZL", 3)) {
481     std::string fixed_scratch("_ZL");
482     fixed_scratch.append(mangled_name.GetCString() + 2);
483     alternates.push_back(ConstString(fixed_scratch));
484   }
485 
486   TypeSubstitutor TS;
487   // `char` is implementation defined as either `signed` or `unsigned`.  As a
488   // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
489   // char, 'h'-unsigned char.  If we're looking for symbols with a signed char
490   // parameter, try finding matches which have the general case 'c'.
491   if (ConstString char_fixup =
492           TS.substitute(mangled_name.GetStringRef(), "a", "c"))
493     alternates.push_back(char_fixup);
494 
495   // long long parameter mangling 'x', may actually just be a long 'l' argument
496   if (ConstString long_fixup =
497           TS.substitute(mangled_name.GetStringRef(), "x", "l"))
498     alternates.push_back(long_fixup);
499 
500   // unsigned long long parameter mangling 'y', may actually just be unsigned
501   // long 'm' argument
502   if (ConstString ulong_fixup =
503           TS.substitute(mangled_name.GetStringRef(), "y", "m"))
504     alternates.push_back(ulong_fixup);
505 
506   if (ConstString ctor_fixup =
507           CtorDtorSubstitutor().substitute(mangled_name.GetStringRef()))
508     alternates.push_back(ctor_fixup);
509 
510   return alternates;
511 }
512 
513 ConstString CPlusPlusLanguage::FindBestAlternateFunctionMangledName(
514     const Mangled mangled, const SymbolContext &sym_ctx) const {
515   ConstString demangled = mangled.GetDemangledName();
516   if (!demangled)
517     return ConstString();
518 
519   CPlusPlusLanguage::MethodName cpp_name(demangled);
520   std::string scope_qualified_name = cpp_name.GetScopeQualifiedName();
521 
522   if (!scope_qualified_name.size())
523     return ConstString();
524 
525   if (!sym_ctx.module_sp)
526     return ConstString();
527 
528   lldb_private::SymbolFile *sym_file = sym_ctx.module_sp->GetSymbolFile();
529   if (!sym_file)
530     return ConstString();
531 
532   std::vector<ConstString> alternates;
533   sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates);
534 
535   std::vector<ConstString> param_and_qual_matches;
536   std::vector<ConstString> param_matches;
537   for (size_t i = 0; i < alternates.size(); i++) {
538     ConstString alternate_mangled_name = alternates[i];
539     Mangled mangled(alternate_mangled_name);
540     ConstString demangled = mangled.GetDemangledName();
541 
542     CPlusPlusLanguage::MethodName alternate_cpp_name(demangled);
543     if (!cpp_name.IsValid())
544       continue;
545 
546     if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments()) {
547       if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers())
548         param_and_qual_matches.push_back(alternate_mangled_name);
549       else
550         param_matches.push_back(alternate_mangled_name);
551     }
552   }
553 
554   if (param_and_qual_matches.size())
555     return param_and_qual_matches[0]; // It is assumed that there will be only
556                                       // one!
557   else if (param_matches.size())
558     return param_matches[0]; // Return one of them as a best match
559   else
560     return ConstString();
561 }
562 
563 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
564   if (!cpp_category_sp)
565     return;
566 
567   TypeSummaryImpl::Flags stl_summary_flags;
568   stl_summary_flags.SetCascades(true)
569       .SetSkipPointers(false)
570       .SetSkipReferences(false)
571       .SetDontShowChildren(true)
572       .SetDontShowValue(true)
573       .SetShowMembersOneLiner(false)
574       .SetHideItemNames(false);
575 
576   AddCXXSummary(cpp_category_sp,
577                 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
578                 "std::string summary provider",
579                 ConstString("^std::__[[:alnum:]]+::string$"), stl_summary_flags,
580                 true);
581   AddCXXSummary(cpp_category_sp,
582                 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
583                 "std::string summary provider",
584                 ConstString("^std::__[[:alnum:]]+::basic_string<char, "
585                             "std::__[[:alnum:]]+::char_traits<char>, "
586                             "std::__[[:alnum:]]+::allocator<char> >$"),
587                 stl_summary_flags, true);
588   AddCXXSummary(cpp_category_sp,
589                 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
590                 "std::string summary provider",
591                 ConstString("^std::__[[:alnum:]]+::basic_string<unsigned char, "
592                             "std::__[[:alnum:]]+::char_traits<unsigned char>, "
593                             "std::__[[:alnum:]]+::allocator<unsigned char> >$"),
594                 stl_summary_flags, true);
595 
596   AddCXXSummary(cpp_category_sp,
597                 lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
598                 "std::u16string summary provider",
599                 ConstString("^std::__[[:alnum:]]+::basic_string<char16_t, "
600                             "std::__[[:alnum:]]+::char_traits<char16_t>, "
601                             "std::__[[:alnum:]]+::allocator<char16_t> >$"),
602                 stl_summary_flags, true);
603 
604   AddCXXSummary(cpp_category_sp,
605                 lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
606                 "std::u32string summary provider",
607                 ConstString("^std::__[[:alnum:]]+::basic_string<char32_t, "
608                             "std::__[[:alnum:]]+::char_traits<char32_t>, "
609                             "std::__[[:alnum:]]+::allocator<char32_t> >$"),
610                 stl_summary_flags, true);
611 
612   AddCXXSummary(
613       cpp_category_sp, lldb_private::formatters::LibcxxWStringSummaryProvider,
614       "std::wstring summary provider",
615       ConstString("^std::__[[:alnum:]]+::wstring$"), stl_summary_flags, true);
616   AddCXXSummary(cpp_category_sp,
617                 lldb_private::formatters::LibcxxWStringSummaryProvider,
618                 "std::wstring summary provider",
619                 ConstString("^std::__[[:alnum:]]+::basic_string<wchar_t, "
620                             "std::__[[:alnum:]]+::char_traits<wchar_t>, "
621                             "std::__[[:alnum:]]+::allocator<wchar_t> >$"),
622                 stl_summary_flags, true);
623 
624   AddCXXSummary(cpp_category_sp,
625                 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
626                 "std::string_view summary provider",
627                 ConstString("^std::__[[:alnum:]]+::string_view$"),
628                 stl_summary_flags, true);
629   AddCXXSummary(cpp_category_sp,
630                 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
631                 "std::string_view summary provider",
632                 ConstString("^std::__[[:alnum:]]+::basic_string_view<char, "
633                             "std::__[[:alnum:]]+::char_traits<char> >$"),
634                 stl_summary_flags, true);
635   AddCXXSummary(
636       cpp_category_sp,
637       lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
638       "std::string_view summary provider",
639       ConstString("^std::__[[:alnum:]]+::basic_string_view<unsigned char, "
640                   "std::__[[:alnum:]]+::char_traits<unsigned char> >$"),
641       stl_summary_flags, true);
642 
643   AddCXXSummary(cpp_category_sp,
644                 lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16,
645                 "std::u16string_view summary provider",
646                 ConstString("^std::__[[:alnum:]]+::basic_string_view<char16_t, "
647                             "std::__[[:alnum:]]+::char_traits<char16_t> >$"),
648                 stl_summary_flags, true);
649 
650   AddCXXSummary(cpp_category_sp,
651                 lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32,
652                 "std::u32string_view summary provider",
653                 ConstString("^std::__[[:alnum:]]+::basic_string_view<char32_t, "
654                             "std::__[[:alnum:]]+::char_traits<char32_t> >$"),
655                 stl_summary_flags, true);
656 
657   AddCXXSummary(cpp_category_sp,
658                 lldb_private::formatters::LibcxxWStringViewSummaryProvider,
659                 "std::wstring_view summary provider",
660                 ConstString("^std::__[[:alnum:]]+::wstring_view$"),
661                 stl_summary_flags, true);
662   AddCXXSummary(cpp_category_sp,
663                 lldb_private::formatters::LibcxxWStringViewSummaryProvider,
664                 "std::wstring_view summary provider",
665                 ConstString("^std::__[[:alnum:]]+::basic_string_view<wchar_t, "
666                             "std::__[[:alnum:]]+::char_traits<wchar_t> >$"),
667                 stl_summary_flags, true);
668 
669   SyntheticChildren::Flags stl_synth_flags;
670   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
671       false);
672   SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
673   stl_deref_flags.SetFrontEndWantsDereference();
674 
675   AddCXXSynthetic(
676       cpp_category_sp,
677       lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator,
678       "libc++ std::bitset synthetic children",
679       ConstString("^std::__[[:alnum:]]+::bitset<.+>(( )?&)?$"), stl_deref_flags,
680       true);
681   AddCXXSynthetic(
682       cpp_category_sp,
683       lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
684       "libc++ std::vector synthetic children",
685       ConstString("^std::__[[:alnum:]]+::vector<.+>(( )?&)?$"), stl_deref_flags,
686       true);
687   AddCXXSynthetic(
688       cpp_category_sp,
689       lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
690       "libc++ std::forward_list synthetic children",
691       ConstString("^std::__[[:alnum:]]+::forward_list<.+>(( )?&)?$"),
692       stl_synth_flags, true);
693   AddCXXSynthetic(
694       cpp_category_sp,
695       lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator,
696       "libc++ std::list synthetic children",
697       // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>(( )?&)?$"
698       // so that it does not clash with: "^std::(__cxx11::)?list<.+>(( )?&)?$"
699       ConstString("^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
700                   "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>(( )?&)?$"),
701       stl_deref_flags, true);
702   AddCXXSynthetic(
703       cpp_category_sp,
704       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
705       "libc++ std::map synthetic children",
706       ConstString("^std::__[[:alnum:]]+::map<.+> >(( )?&)?$"), stl_synth_flags,
707       true);
708   AddCXXSynthetic(
709       cpp_category_sp,
710       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
711       "libc++ std::set synthetic children",
712       ConstString("^std::__[[:alnum:]]+::set<.+> >(( )?&)?$"), stl_deref_flags,
713       true);
714   AddCXXSynthetic(
715       cpp_category_sp,
716       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
717       "libc++ std::multiset synthetic children",
718       ConstString("^std::__[[:alnum:]]+::multiset<.+> >(( )?&)?$"),
719       stl_deref_flags, true);
720   AddCXXSynthetic(
721       cpp_category_sp,
722       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
723       "libc++ std::multimap synthetic children",
724       ConstString("^std::__[[:alnum:]]+::multimap<.+> >(( )?&)?$"),
725       stl_synth_flags, true);
726   AddCXXSynthetic(
727       cpp_category_sp,
728       lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator,
729       "libc++ std::unordered containers synthetic children",
730       ConstString("^(std::__[[:alnum:]]+::)unordered_(multi)?(map|set)<.+> >$"),
731       stl_synth_flags, true);
732   AddCXXSynthetic(
733       cpp_category_sp,
734       lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
735       "libc++ std::initializer_list synthetic children",
736       ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags,
737       true);
738   AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator,
739                   "libc++ std::queue synthetic children",
740                   ConstString("^std::__[[:alnum:]]+::queue<.+>(( )?&)?$"),
741                   stl_synth_flags, true);
742   AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator,
743                   "libc++ std::tuple synthetic children",
744                   ConstString("^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$"),
745                   stl_synth_flags, true);
746   AddCXXSynthetic(cpp_category_sp, LibcxxOptionalSyntheticFrontEndCreator,
747                   "libc++ std::optional synthetic children",
748                   ConstString("^std::__[[:alnum:]]+::optional<.+>(( )?&)?$"),
749                   stl_synth_flags, true);
750   AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator,
751                   "libc++ std::variant synthetic children",
752                   ConstString("^std::__[[:alnum:]]+::variant<.+>(( )?&)?$"),
753                   stl_synth_flags, true);
754   AddCXXSynthetic(
755       cpp_category_sp,
756       lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
757       "libc++ std::atomic synthetic children",
758       ConstString("^std::__[[:alnum:]]+::atomic<.+>$"), stl_synth_flags, true);
759   AddCXXSynthetic(
760       cpp_category_sp,
761       lldb_private::formatters::LibcxxStdSpanSyntheticFrontEndCreator,
762       "libc++ std::span synthetic children",
763       ConstString("^std::__[[:alnum:]]+::span<.+>(( )?&)?$"), stl_deref_flags,
764       true);
765 
766   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
767       RegularExpression("^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$"),
768       SyntheticChildrenSP(new ScriptedSyntheticChildren(
769           stl_synth_flags,
770           "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
771 
772   AddCXXSynthetic(
773       cpp_category_sp,
774       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
775       "shared_ptr synthetic children",
776       ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"),
777       stl_synth_flags, true);
778 
779   ConstString libcxx_std_unique_ptr_regex(
780       "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$");
781   AddCXXSynthetic(
782       cpp_category_sp,
783       lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator,
784       "unique_ptr synthetic children", libcxx_std_unique_ptr_regex,
785       stl_synth_flags, true);
786 
787   AddCXXSynthetic(
788       cpp_category_sp,
789       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
790       "weak_ptr synthetic children",
791       ConstString("^(std::__[[:alnum:]]+::)weak_ptr<.+>(( )?&)?$"),
792       stl_synth_flags, true);
793   AddCXXSummary(cpp_category_sp,
794                 lldb_private::formatters::LibcxxFunctionSummaryProvider,
795                 "libc++ std::function summary provider",
796                 ConstString("^std::__[[:alnum:]]+::function<.+>$"),
797                 stl_summary_flags, true);
798 
799   stl_summary_flags.SetDontShowChildren(false);
800   stl_summary_flags.SetSkipPointers(false);
801   AddCXXSummary(cpp_category_sp,
802                 lldb_private::formatters::LibcxxContainerSummaryProvider,
803                 "libc++ std::bitset summary provider",
804                 ConstString("^std::__[[:alnum:]]+::bitset<.+>(( )?&)?$"),
805                 stl_summary_flags, true);
806   AddCXXSummary(cpp_category_sp,
807                 lldb_private::formatters::LibcxxContainerSummaryProvider,
808                 "libc++ std::vector summary provider",
809                 ConstString("^std::__[[:alnum:]]+::vector<.+>(( )?&)?$"),
810                 stl_summary_flags, true);
811   AddCXXSummary(cpp_category_sp,
812                 lldb_private::formatters::LibcxxContainerSummaryProvider,
813                 "libc++ std::list summary provider",
814                 ConstString("^std::__[[:alnum:]]+::forward_list<.+>(( )?&)?$"),
815                 stl_summary_flags, true);
816   AddCXXSummary(
817       cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
818       "libc++ std::list summary provider",
819       // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>(( )?&)?$"
820       // so that it does not clash with: "^std::(__cxx11::)?list<.+>(( )?&)?$"
821       ConstString("^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
822                   "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>(( )?&)?$"),
823       stl_summary_flags, true);
824   AddCXXSummary(cpp_category_sp,
825                 lldb_private::formatters::LibcxxContainerSummaryProvider,
826                 "libc++ std::map summary provider",
827                 ConstString("^std::__[[:alnum:]]+::map<.+>(( )?&)?$"),
828                 stl_summary_flags, true);
829   AddCXXSummary(cpp_category_sp,
830                 lldb_private::formatters::LibcxxContainerSummaryProvider,
831                 "libc++ std::deque summary provider",
832                 ConstString("^std::__[[:alnum:]]+::deque<.+>(( )?&)?$"),
833                 stl_summary_flags, true);
834   AddCXXSummary(cpp_category_sp,
835                 lldb_private::formatters::LibcxxContainerSummaryProvider,
836                 "libc++ std::queue summary provider",
837                 ConstString("^std::__[[:alnum:]]+::queue<.+>(( )?&)?$"),
838                 stl_summary_flags, true);
839   AddCXXSummary(cpp_category_sp,
840                 lldb_private::formatters::LibcxxContainerSummaryProvider,
841                 "libc++ std::set summary provider",
842                 ConstString("^std::__[[:alnum:]]+::set<.+>(( )?&)?$"),
843                 stl_summary_flags, true);
844   AddCXXSummary(cpp_category_sp,
845                 lldb_private::formatters::LibcxxContainerSummaryProvider,
846                 "libc++ std::multiset summary provider",
847                 ConstString("^std::__[[:alnum:]]+::multiset<.+>(( )?&)?$"),
848                 stl_summary_flags, true);
849   AddCXXSummary(cpp_category_sp,
850                 lldb_private::formatters::LibcxxContainerSummaryProvider,
851                 "libc++ std::multimap summary provider",
852                 ConstString("^std::__[[:alnum:]]+::multimap<.+>(( )?&)?$"),
853                 stl_summary_flags, true);
854   AddCXXSummary(
855       cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
856       "libc++ std::unordered containers summary provider",
857       ConstString("^(std::__[[:alnum:]]+::)unordered_(multi)?(map|set)<.+> >$"),
858       stl_summary_flags, true);
859   AddCXXSummary(cpp_category_sp, LibcxxContainerSummaryProvider,
860                 "libc++ std::tuple summary provider",
861                 ConstString("^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$"),
862                 stl_summary_flags, true);
863   AddCXXSummary(cpp_category_sp,
864                 lldb_private::formatters::LibCxxAtomicSummaryProvider,
865                 "libc++ std::atomic summary provider",
866                 ConstString("^std::__[[:alnum:]]+::atomic<.+>$"),
867                 stl_summary_flags, true);
868   AddCXXSummary(cpp_category_sp,
869                 lldb_private::formatters::GenericOptionalSummaryProvider,
870                 "libc++ std::optional summary provider",
871                 ConstString("^std::__[[:alnum:]]+::optional<.+>(( )?&)?$"),
872                 stl_summary_flags, true);
873   AddCXXSummary(cpp_category_sp,
874                 lldb_private::formatters::LibcxxVariantSummaryProvider,
875                 "libc++ std::variant summary provider",
876                 ConstString("^std::__[[:alnum:]]+::variant<.+>(( )?&)?$"),
877                 stl_summary_flags, true);
878   AddCXXSummary(cpp_category_sp,
879                 lldb_private::formatters::LibcxxContainerSummaryProvider,
880                 "libc++ std::span summary provider",
881                 ConstString("^std::__[[:alnum:]]+::span<.+>(( )?&)?$"),
882                 stl_summary_flags, true);
883 
884   stl_summary_flags.SetSkipPointers(true);
885 
886   AddCXXSummary(cpp_category_sp,
887                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
888                 "libc++ std::shared_ptr summary provider",
889                 ConstString("^std::__[[:alnum:]]+::shared_ptr<.+>(( )?&)?$"),
890                 stl_summary_flags, true);
891   AddCXXSummary(cpp_category_sp,
892                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
893                 "libc++ std::weak_ptr summary provider",
894                 ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"),
895                 stl_summary_flags, true);
896   AddCXXSummary(cpp_category_sp,
897                 lldb_private::formatters::LibcxxUniquePointerSummaryProvider,
898                 "libc++ std::unique_ptr summary provider",
899                 libcxx_std_unique_ptr_regex, stl_summary_flags, true);
900 
901   AddCXXSynthetic(
902       cpp_category_sp,
903       lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator,
904       "std::vector iterator synthetic children",
905       ConstString("^std::__[[:alnum:]]+::__wrap_iter<.+>$"), stl_synth_flags,
906       true);
907 
908   AddCXXSynthetic(
909       cpp_category_sp,
910       lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
911       "std::map iterator synthetic children",
912       ConstString("^std::__[[:alnum:]]+::__map_(const_)?iterator<.+>$"), stl_synth_flags,
913       true);
914 
915   AddCXXSynthetic(
916       cpp_category_sp,
917       lldb_private::formatters::
918           LibCxxUnorderedMapIteratorSyntheticFrontEndCreator,
919       "std::unordered_map iterator synthetic children",
920       ConstString("^std::__[[:alnum:]]+::__hash_map_(const_)?iterator<.+>$"),
921       stl_synth_flags, true);
922 }
923 
924 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
925   if (!cpp_category_sp)
926     return;
927 
928   TypeSummaryImpl::Flags stl_summary_flags;
929   stl_summary_flags.SetCascades(true)
930       .SetSkipPointers(false)
931       .SetSkipReferences(false)
932       .SetDontShowChildren(true)
933       .SetDontShowValue(true)
934       .SetShowMembersOneLiner(false)
935       .SetHideItemNames(false);
936 
937   lldb::TypeSummaryImplSP std_string_summary_sp(
938       new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}"));
939 
940   lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(
941       stl_summary_flags, LibStdcppStringSummaryProvider,
942       "libstdc++ c++11 std::string summary provider"));
943   lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(
944       stl_summary_flags, LibStdcppWStringSummaryProvider,
945       "libstdc++ c++11 std::wstring summary provider"));
946 
947   cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
948                                                     std_string_summary_sp);
949   cpp_category_sp->GetTypeSummariesContainer()->Add(
950       ConstString("std::basic_string<char>"), std_string_summary_sp);
951   cpp_category_sp->GetTypeSummariesContainer()->Add(
952       ConstString("std::basic_string<char,std::char_traits<char>,std::"
953                   "allocator<char> >"),
954       std_string_summary_sp);
955   cpp_category_sp->GetTypeSummariesContainer()->Add(
956       ConstString("std::basic_string<char, std::char_traits<char>, "
957                   "std::allocator<char> >"),
958       std_string_summary_sp);
959 
960   cpp_category_sp->GetTypeSummariesContainer()->Add(
961       ConstString("std::__cxx11::string"), cxx11_string_summary_sp);
962   cpp_category_sp->GetTypeSummariesContainer()->Add(
963       ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, "
964                   "std::allocator<char> >"),
965       cxx11_string_summary_sp);
966   cpp_category_sp->GetTypeSummariesContainer()->Add(
967       ConstString("std::__cxx11::basic_string<unsigned char, "
968                   "std::char_traits<unsigned char>, "
969                   "std::allocator<unsigned char> >"),
970       cxx11_string_summary_sp);
971 
972   // making sure we force-pick the summary for printing wstring (_M_p is a
973   // wchar_t*)
974   lldb::TypeSummaryImplSP std_wstring_summary_sp(
975       new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
976 
977   cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"),
978                                                     std_wstring_summary_sp);
979   cpp_category_sp->GetTypeSummariesContainer()->Add(
980       ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp);
981   cpp_category_sp->GetTypeSummariesContainer()->Add(
982       ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::"
983                   "allocator<wchar_t> >"),
984       std_wstring_summary_sp);
985   cpp_category_sp->GetTypeSummariesContainer()->Add(
986       ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, "
987                   "std::allocator<wchar_t> >"),
988       std_wstring_summary_sp);
989 
990   cpp_category_sp->GetTypeSummariesContainer()->Add(
991       ConstString("std::__cxx11::wstring"), cxx11_wstring_summary_sp);
992   cpp_category_sp->GetTypeSummariesContainer()->Add(
993       ConstString("std::__cxx11::basic_string<wchar_t, "
994                   "std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
995       cxx11_wstring_summary_sp);
996 
997   SyntheticChildren::Flags stl_synth_flags;
998   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
999       false);
1000   SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
1001   stl_deref_flags.SetFrontEndWantsDereference();
1002 
1003   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1004       RegularExpression("^std::vector<.+>(( )?&)?$"),
1005       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1006           stl_synth_flags,
1007           "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
1008   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1009       RegularExpression("^std::map<.+> >(( )?&)?$"),
1010       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1011           stl_synth_flags,
1012           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1013   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1014       RegularExpression("^std::deque<.+>(( )?&)?$"),
1015       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1016           stl_deref_flags,
1017           "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider")));
1018   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1019       RegularExpression("^std::set<.+> >(( )?&)?$"),
1020       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1021           stl_deref_flags,
1022           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1023   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1024       RegularExpression("^std::multimap<.+> >(( )?&)?$"),
1025       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1026           stl_deref_flags,
1027           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1028   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1029       RegularExpression("^std::multiset<.+> >(( )?&)?$"),
1030       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1031           stl_deref_flags,
1032           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1033   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1034       RegularExpression("^std::unordered_(multi)?(map|set)<.+> >$"),
1035       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1036           stl_deref_flags,
1037           "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")));
1038   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1039       RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"),
1040       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1041           stl_deref_flags,
1042           "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
1043   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1044       RegularExpression("^std::(__cxx11::)?forward_list<.+>(( )?&)?$"),
1045       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1046           stl_synth_flags,
1047           "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
1048 
1049   stl_summary_flags.SetDontShowChildren(false);
1050   stl_summary_flags.SetSkipPointers(false);
1051   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1052       RegularExpression("^std::bitset<.+>(( )?&)?$"),
1053       TypeSummaryImplSP(
1054           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1055   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1056       RegularExpression("^std::vector<.+>(( )?&)?$"),
1057       TypeSummaryImplSP(
1058           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1059   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1060       RegularExpression("^std::map<.+> >(( )?&)?$"),
1061       TypeSummaryImplSP(
1062           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1063   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1064       RegularExpression("^std::set<.+> >(( )?&)?$"),
1065       TypeSummaryImplSP(
1066           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1067   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1068       RegularExpression("^std::deque<.+>(( )?&)?$"),
1069       TypeSummaryImplSP(
1070           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1071   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1072       RegularExpression("^std::multimap<.+> >(( )?&)?$"),
1073       TypeSummaryImplSP(
1074           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1075   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1076       RegularExpression("^std::multiset<.+> >(( )?&)?$"),
1077       TypeSummaryImplSP(
1078           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1079   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1080       RegularExpression("^std::unordered_(multi)?(map|set)<.+> >$"),
1081       TypeSummaryImplSP(
1082           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1083   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1084       RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"),
1085       TypeSummaryImplSP(
1086           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1087   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1088       RegularExpression("^std::(__cxx11::)?forward_list<.+>(( )?&)?$"),
1089       TypeSummaryImplSP(
1090           new ScriptSummaryFormat(stl_summary_flags, "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")));
1091 
1092   AddCXXSynthetic(
1093       cpp_category_sp,
1094       lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator,
1095       "std::vector iterator synthetic children",
1096       ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
1097 
1098   AddCXXSynthetic(
1099       cpp_category_sp,
1100       lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator,
1101       "std::map iterator synthetic children",
1102       ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
1103 
1104   AddCXXSynthetic(
1105       cpp_category_sp,
1106       lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
1107       "std::unique_ptr synthetic children",
1108       ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
1109   AddCXXSynthetic(
1110       cpp_category_sp,
1111       lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
1112       "std::shared_ptr synthetic children",
1113       ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
1114   AddCXXSynthetic(
1115       cpp_category_sp,
1116       lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
1117       "std::weak_ptr synthetic children",
1118       ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
1119   AddCXXSynthetic(
1120       cpp_category_sp,
1121       lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
1122       "std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"),
1123       stl_synth_flags, true);
1124 
1125   AddCXXSynthetic(
1126       cpp_category_sp,
1127       lldb_private::formatters::LibStdcppBitsetSyntheticFrontEndCreator,
1128       "std::bitset synthetic child", ConstString("^std::bitset<.+>(( )?&)?$"),
1129       stl_deref_flags, true);
1130 
1131   AddCXXSynthetic(
1132       cpp_category_sp,
1133       lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator,
1134       "std::optional synthetic child",
1135       ConstString("^std::optional<.+>(( )?&)?$"), stl_deref_flags, true);
1136 
1137   AddCXXSummary(cpp_category_sp,
1138                 lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
1139                 "libstdc++ std::unique_ptr summary provider",
1140                 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_summary_flags,
1141                 true);
1142   AddCXXSummary(cpp_category_sp,
1143                 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
1144                 "libstdc++ std::shared_ptr summary provider",
1145                 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags,
1146                 true);
1147   AddCXXSummary(cpp_category_sp,
1148                 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
1149                 "libstdc++ std::weak_ptr summary provider",
1150                 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags,
1151                 true);
1152   AddCXXSummary(
1153       cpp_category_sp, lldb_private::formatters::GenericOptionalSummaryProvider,
1154       "libstd++ std::optional summary provider",
1155       ConstString("^std::optional<.+>(( )?&)?$"), stl_summary_flags, true);
1156 }
1157 
1158 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1159   if (!cpp_category_sp)
1160     return;
1161 
1162   TypeSummaryImpl::Flags string_flags;
1163   string_flags.SetCascades(true)
1164       .SetSkipPointers(true)
1165       .SetSkipReferences(false)
1166       .SetDontShowChildren(true)
1167       .SetDontShowValue(false)
1168       .SetShowMembersOneLiner(false)
1169       .SetHideItemNames(false);
1170 
1171   TypeSummaryImpl::Flags string_array_flags;
1172   string_array_flags.SetCascades(true)
1173       .SetSkipPointers(true)
1174       .SetSkipReferences(false)
1175       .SetDontShowChildren(true)
1176       .SetDontShowValue(true)
1177       .SetShowMembersOneLiner(false)
1178       .SetHideItemNames(false);
1179 
1180   AddCXXSummary(
1181       cpp_category_sp, lldb_private::formatters::Char8StringSummaryProvider,
1182       "char8_t * summary provider", ConstString("char8_t *"), string_flags);
1183   AddCXXSummary(cpp_category_sp,
1184                 lldb_private::formatters::Char8StringSummaryProvider,
1185                 "char8_t [] summary provider",
1186                 ConstString("char8_t ?\\[[0-9]+\\]"), string_array_flags, true);
1187 
1188   AddCXXSummary(
1189       cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
1190       "char16_t * summary provider", ConstString("char16_t *"), string_flags);
1191   AddCXXSummary(cpp_category_sp,
1192                 lldb_private::formatters::Char16StringSummaryProvider,
1193                 "char16_t [] summary provider",
1194                 ConstString("char16_t ?\\[[0-9]+\\]"), string_array_flags, true);
1195 
1196   AddCXXSummary(
1197       cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider,
1198       "char32_t * summary provider", ConstString("char32_t *"), string_flags);
1199   AddCXXSummary(cpp_category_sp,
1200                 lldb_private::formatters::Char32StringSummaryProvider,
1201                 "char32_t [] summary provider",
1202                 ConstString("char32_t ?\\[[0-9]+\\]"), string_array_flags, true);
1203 
1204   AddCXXSummary(
1205       cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider,
1206       "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
1207   AddCXXSummary(cpp_category_sp,
1208                 lldb_private::formatters::WCharStringSummaryProvider,
1209                 "wchar_t * summary provider",
1210                 ConstString("wchar_t ?\\[[0-9]+\\]"), string_array_flags, true);
1211 
1212   AddCXXSummary(
1213       cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
1214       "unichar * summary provider", ConstString("unichar *"), string_flags);
1215 
1216   TypeSummaryImpl::Flags widechar_flags;
1217   widechar_flags.SetDontShowValue(true)
1218       .SetSkipPointers(true)
1219       .SetSkipReferences(false)
1220       .SetCascades(true)
1221       .SetDontShowChildren(true)
1222       .SetHideItemNames(true)
1223       .SetShowMembersOneLiner(false);
1224 
1225   AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char8SummaryProvider,
1226                 "char8_t summary provider", ConstString("char8_t"),
1227                 widechar_flags);
1228   AddCXXSummary(
1229       cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
1230       "char16_t summary provider", ConstString("char16_t"), widechar_flags);
1231   AddCXXSummary(
1232       cpp_category_sp, lldb_private::formatters::Char32SummaryProvider,
1233       "char32_t summary provider", ConstString("char32_t"), widechar_flags);
1234   AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider,
1235                 "wchar_t summary provider", ConstString("wchar_t"),
1236                 widechar_flags);
1237 
1238   AddCXXSummary(
1239       cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
1240       "unichar summary provider", ConstString("unichar"), widechar_flags);
1241 }
1242 
1243 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() {
1244   class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger {
1245   public:
1246     CompilerType AdjustForInclusion(CompilerType &candidate) override {
1247       LanguageType lang_type(candidate.GetMinimumLanguage());
1248       if (!Language::LanguageIsC(lang_type) &&
1249           !Language::LanguageIsCPlusPlus(lang_type))
1250         return CompilerType();
1251       if (candidate.IsTypedefType())
1252         return candidate.GetTypedefedType();
1253       return candidate;
1254     }
1255   };
1256 
1257   return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
1258 }
1259 
1260 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
1261   static llvm::once_flag g_initialize;
1262   static TypeCategoryImplSP g_category;
1263 
1264   llvm::call_once(g_initialize, [this]() -> void {
1265     DataVisualization::Categories::GetCategory(ConstString(GetPluginName()),
1266                                                g_category);
1267     if (g_category) {
1268       LoadLibStdcppFormatters(g_category);
1269       LoadLibCxxFormatters(g_category);
1270       LoadSystemFormatters(g_category);
1271     }
1272   });
1273   return g_category;
1274 }
1275 
1276 HardcodedFormatters::HardcodedSummaryFinder
1277 CPlusPlusLanguage::GetHardcodedSummaries() {
1278   static llvm::once_flag g_initialize;
1279   static ConstString g_vectortypes("VectorTypes");
1280   static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
1281 
1282   llvm::call_once(g_initialize, []() -> void {
1283     g_formatters.push_back(
1284         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1285            FormatManager &) -> TypeSummaryImpl::SharedPointer {
1286           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1287               new CXXFunctionSummaryFormat(
1288                   TypeSummaryImpl::Flags(),
1289                   lldb_private::formatters::CXXFunctionPointerSummaryProvider,
1290                   "Function pointer summary provider"));
1291           if (valobj.GetCompilerType().IsFunctionPointerType()) {
1292             return formatter_sp;
1293           }
1294           return nullptr;
1295         });
1296     g_formatters.push_back(
1297         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1298            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1299           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1300               new CXXFunctionSummaryFormat(
1301                   TypeSummaryImpl::Flags()
1302                       .SetCascades(true)
1303                       .SetDontShowChildren(true)
1304                       .SetHideItemNames(true)
1305                       .SetShowMembersOneLiner(true)
1306                       .SetSkipPointers(true)
1307                       .SetSkipReferences(false),
1308                   lldb_private::formatters::VectorTypeSummaryProvider,
1309                   "vector_type pointer summary provider"));
1310           if (valobj.GetCompilerType().IsVectorType()) {
1311             if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1312               return formatter_sp;
1313           }
1314           return nullptr;
1315         });
1316     g_formatters.push_back(
1317         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1318            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1319           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1320               new CXXFunctionSummaryFormat(
1321                   TypeSummaryImpl::Flags()
1322                       .SetCascades(true)
1323                       .SetDontShowChildren(true)
1324                       .SetHideItemNames(true)
1325                       .SetShowMembersOneLiner(true)
1326                       .SetSkipPointers(true)
1327                       .SetSkipReferences(false),
1328                   lldb_private::formatters::BlockPointerSummaryProvider,
1329                   "block pointer summary provider"));
1330           if (valobj.GetCompilerType().IsBlockPointerType()) {
1331             return formatter_sp;
1332           }
1333           return nullptr;
1334         });
1335   });
1336 
1337   return g_formatters;
1338 }
1339 
1340 HardcodedFormatters::HardcodedSyntheticFinder
1341 CPlusPlusLanguage::GetHardcodedSynthetics() {
1342   static llvm::once_flag g_initialize;
1343   static ConstString g_vectortypes("VectorTypes");
1344   static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
1345 
1346   llvm::call_once(g_initialize, []() -> void {
1347     g_formatters.push_back([](lldb_private::ValueObject &valobj,
1348                               lldb::DynamicValueType, FormatManager &fmt_mgr)
1349                                -> SyntheticChildren::SharedPointer {
1350       static CXXSyntheticChildren::SharedPointer formatter_sp(
1351           new CXXSyntheticChildren(
1352               SyntheticChildren::Flags()
1353                   .SetCascades(true)
1354                   .SetSkipPointers(true)
1355                   .SetSkipReferences(true)
1356                   .SetNonCacheable(true),
1357               "vector_type synthetic children",
1358               lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
1359       if (valobj.GetCompilerType().IsVectorType()) {
1360         if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1361           return formatter_sp;
1362       }
1363       return nullptr;
1364     });
1365     g_formatters.push_back([](lldb_private::ValueObject &valobj,
1366                               lldb::DynamicValueType, FormatManager &fmt_mgr)
1367                                -> SyntheticChildren::SharedPointer {
1368       static CXXSyntheticChildren::SharedPointer formatter_sp(
1369           new CXXSyntheticChildren(
1370               SyntheticChildren::Flags()
1371                   .SetCascades(true)
1372                   .SetSkipPointers(true)
1373                   .SetSkipReferences(true)
1374                   .SetNonCacheable(true),
1375               "block pointer synthetic children",
1376               lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
1377       if (valobj.GetCompilerType().IsBlockPointerType()) {
1378         return formatter_sp;
1379       }
1380       return nullptr;
1381     });
1382   });
1383 
1384   return g_formatters;
1385 }
1386 
1387 bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) {
1388   if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) ||
1389       !valobj.IsPointerType())
1390     return false;
1391   bool canReadValue = true;
1392   bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
1393   return canReadValue && isZero;
1394 }
1395 
1396 bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
1397   const auto suffixes = {".cpp", ".cxx", ".c++", ".cc",  ".c",
1398                          ".h",   ".hh",  ".hpp", ".hxx", ".h++"};
1399   for (auto suffix : suffixes) {
1400     if (file_path.endswith_insensitive(suffix))
1401       return true;
1402   }
1403 
1404   // Check if we're in a STL path (where the files usually have no extension
1405   // that we could check for.
1406   return file_path.contains("/usr/include/c++/");
1407 }
1408