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.getValue().name.basename;
222         m_context = function.getValue().name.context;
223         m_arguments = function.getValue().arguments;
224         m_qualifiers = function.getValue().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.getValue().basename;
333     context = full_name.getValue().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;
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 
760   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
761       RegularExpression("^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$"),
762       SyntheticChildrenSP(new ScriptedSyntheticChildren(
763           stl_synth_flags,
764           "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
765 
766   AddCXXSynthetic(
767       cpp_category_sp,
768       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
769       "shared_ptr synthetic children",
770       ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"),
771       stl_synth_flags, true);
772 
773   ConstString libcxx_std_unique_ptr_regex(
774       "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$");
775   AddCXXSynthetic(
776       cpp_category_sp,
777       lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator,
778       "unique_ptr synthetic children", libcxx_std_unique_ptr_regex,
779       stl_synth_flags, true);
780 
781   AddCXXSynthetic(
782       cpp_category_sp,
783       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
784       "weak_ptr synthetic children",
785       ConstString("^(std::__[[:alnum:]]+::)weak_ptr<.+>(( )?&)?$"),
786       stl_synth_flags, true);
787   AddCXXSummary(cpp_category_sp,
788                 lldb_private::formatters::LibcxxFunctionSummaryProvider,
789                 "libc++ std::function summary provider",
790                 ConstString("^std::__[[:alnum:]]+::function<.+>$"),
791                 stl_summary_flags, true);
792 
793   stl_summary_flags.SetDontShowChildren(false);
794   stl_summary_flags.SetSkipPointers(false);
795   AddCXXSummary(cpp_category_sp,
796                 lldb_private::formatters::LibcxxContainerSummaryProvider,
797                 "libc++ std::bitset summary provider",
798                 ConstString("^std::__[[:alnum:]]+::bitset<.+>(( )?&)?$"),
799                 stl_summary_flags, true);
800   AddCXXSummary(cpp_category_sp,
801                 lldb_private::formatters::LibcxxContainerSummaryProvider,
802                 "libc++ std::vector summary provider",
803                 ConstString("^std::__[[:alnum:]]+::vector<.+>(( )?&)?$"),
804                 stl_summary_flags, true);
805   AddCXXSummary(cpp_category_sp,
806                 lldb_private::formatters::LibcxxContainerSummaryProvider,
807                 "libc++ std::list summary provider",
808                 ConstString("^std::__[[:alnum:]]+::forward_list<.+>(( )?&)?$"),
809                 stl_summary_flags, true);
810   AddCXXSummary(
811       cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
812       "libc++ std::list summary provider",
813       // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>(( )?&)?$"
814       // so that it does not clash with: "^std::(__cxx11::)?list<.+>(( )?&)?$"
815       ConstString("^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
816                   "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>(( )?&)?$"),
817       stl_summary_flags, true);
818   AddCXXSummary(cpp_category_sp,
819                 lldb_private::formatters::LibcxxContainerSummaryProvider,
820                 "libc++ std::map summary provider",
821                 ConstString("^std::__[[:alnum:]]+::map<.+>(( )?&)?$"),
822                 stl_summary_flags, true);
823   AddCXXSummary(cpp_category_sp,
824                 lldb_private::formatters::LibcxxContainerSummaryProvider,
825                 "libc++ std::deque summary provider",
826                 ConstString("^std::__[[:alnum:]]+::deque<.+>(( )?&)?$"),
827                 stl_summary_flags, true);
828   AddCXXSummary(cpp_category_sp,
829                 lldb_private::formatters::LibcxxContainerSummaryProvider,
830                 "libc++ std::queue summary provider",
831                 ConstString("^std::__[[:alnum:]]+::queue<.+>(( )?&)?$"),
832                 stl_summary_flags, true);
833   AddCXXSummary(cpp_category_sp,
834                 lldb_private::formatters::LibcxxContainerSummaryProvider,
835                 "libc++ std::set summary provider",
836                 ConstString("^std::__[[:alnum:]]+::set<.+>(( )?&)?$"),
837                 stl_summary_flags, true);
838   AddCXXSummary(cpp_category_sp,
839                 lldb_private::formatters::LibcxxContainerSummaryProvider,
840                 "libc++ std::multiset summary provider",
841                 ConstString("^std::__[[:alnum:]]+::multiset<.+>(( )?&)?$"),
842                 stl_summary_flags, true);
843   AddCXXSummary(cpp_category_sp,
844                 lldb_private::formatters::LibcxxContainerSummaryProvider,
845                 "libc++ std::multimap summary provider",
846                 ConstString("^std::__[[:alnum:]]+::multimap<.+>(( )?&)?$"),
847                 stl_summary_flags, true);
848   AddCXXSummary(
849       cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
850       "libc++ std::unordered containers summary provider",
851       ConstString("^(std::__[[:alnum:]]+::)unordered_(multi)?(map|set)<.+> >$"),
852       stl_summary_flags, true);
853   AddCXXSummary(cpp_category_sp, LibcxxContainerSummaryProvider,
854                 "libc++ std::tuple summary provider",
855                 ConstString("^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$"),
856                 stl_summary_flags, true);
857   AddCXXSummary(cpp_category_sp,
858                 lldb_private::formatters::LibCxxAtomicSummaryProvider,
859                 "libc++ std::atomic summary provider",
860                 ConstString("^std::__[[:alnum:]]+::atomic<.+>$"),
861                 stl_summary_flags, true);
862   AddCXXSummary(cpp_category_sp,
863                 lldb_private::formatters::GenericOptionalSummaryProvider,
864                 "libc++ std::optional summary provider",
865                 ConstString("^std::__[[:alnum:]]+::optional<.+>(( )?&)?$"),
866                 stl_summary_flags, true);
867   AddCXXSummary(cpp_category_sp,
868                 lldb_private::formatters::LibcxxVariantSummaryProvider,
869                 "libc++ std::variant summary provider",
870                 ConstString("^std::__[[:alnum:]]+::variant<.+>(( )?&)?$"),
871                 stl_summary_flags, true);
872 
873   stl_summary_flags.SetSkipPointers(true);
874 
875   AddCXXSummary(cpp_category_sp,
876                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
877                 "libc++ std::shared_ptr summary provider",
878                 ConstString("^std::__[[:alnum:]]+::shared_ptr<.+>(( )?&)?$"),
879                 stl_summary_flags, true);
880   AddCXXSummary(cpp_category_sp,
881                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
882                 "libc++ std::weak_ptr summary provider",
883                 ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"),
884                 stl_summary_flags, true);
885   AddCXXSummary(cpp_category_sp,
886                 lldb_private::formatters::LibcxxUniquePointerSummaryProvider,
887                 "libc++ std::unique_ptr summary provider",
888                 libcxx_std_unique_ptr_regex, stl_summary_flags, true);
889 
890   AddCXXSynthetic(
891       cpp_category_sp,
892       lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator,
893       "std::vector iterator synthetic children",
894       ConstString("^std::__[[:alnum:]]+::__wrap_iter<.+>$"), stl_synth_flags,
895       true);
896 
897   AddCXXSynthetic(
898       cpp_category_sp,
899       lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
900       "std::map iterator synthetic children",
901       ConstString("^std::__[[:alnum:]]+::__map_iterator<.+>$"), stl_synth_flags,
902       true);
903 }
904 
905 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
906   if (!cpp_category_sp)
907     return;
908 
909   TypeSummaryImpl::Flags stl_summary_flags;
910   stl_summary_flags.SetCascades(true)
911       .SetSkipPointers(false)
912       .SetSkipReferences(false)
913       .SetDontShowChildren(true)
914       .SetDontShowValue(true)
915       .SetShowMembersOneLiner(false)
916       .SetHideItemNames(false);
917 
918   lldb::TypeSummaryImplSP std_string_summary_sp(
919       new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}"));
920 
921   lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(
922       stl_summary_flags, LibStdcppStringSummaryProvider,
923       "libstdc++ c++11 std::string summary provider"));
924   lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(
925       stl_summary_flags, LibStdcppWStringSummaryProvider,
926       "libstdc++ c++11 std::wstring summary provider"));
927 
928   cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
929                                                     std_string_summary_sp);
930   cpp_category_sp->GetTypeSummariesContainer()->Add(
931       ConstString("std::basic_string<char>"), std_string_summary_sp);
932   cpp_category_sp->GetTypeSummariesContainer()->Add(
933       ConstString("std::basic_string<char,std::char_traits<char>,std::"
934                   "allocator<char> >"),
935       std_string_summary_sp);
936   cpp_category_sp->GetTypeSummariesContainer()->Add(
937       ConstString("std::basic_string<char, std::char_traits<char>, "
938                   "std::allocator<char> >"),
939       std_string_summary_sp);
940 
941   cpp_category_sp->GetTypeSummariesContainer()->Add(
942       ConstString("std::__cxx11::string"), cxx11_string_summary_sp);
943   cpp_category_sp->GetTypeSummariesContainer()->Add(
944       ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, "
945                   "std::allocator<char> >"),
946       cxx11_string_summary_sp);
947   cpp_category_sp->GetTypeSummariesContainer()->Add(
948       ConstString("std::__cxx11::basic_string<unsigned char, "
949                   "std::char_traits<unsigned char>, "
950                   "std::allocator<unsigned char> >"),
951       cxx11_string_summary_sp);
952 
953   // making sure we force-pick the summary for printing wstring (_M_p is a
954   // wchar_t*)
955   lldb::TypeSummaryImplSP std_wstring_summary_sp(
956       new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
957 
958   cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"),
959                                                     std_wstring_summary_sp);
960   cpp_category_sp->GetTypeSummariesContainer()->Add(
961       ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp);
962   cpp_category_sp->GetTypeSummariesContainer()->Add(
963       ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::"
964                   "allocator<wchar_t> >"),
965       std_wstring_summary_sp);
966   cpp_category_sp->GetTypeSummariesContainer()->Add(
967       ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, "
968                   "std::allocator<wchar_t> >"),
969       std_wstring_summary_sp);
970 
971   cpp_category_sp->GetTypeSummariesContainer()->Add(
972       ConstString("std::__cxx11::wstring"), cxx11_wstring_summary_sp);
973   cpp_category_sp->GetTypeSummariesContainer()->Add(
974       ConstString("std::__cxx11::basic_string<wchar_t, "
975                   "std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
976       cxx11_wstring_summary_sp);
977 
978   SyntheticChildren::Flags stl_synth_flags;
979   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
980       false);
981   SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
982   stl_deref_flags.SetFrontEndWantsDereference();
983 
984   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
985       RegularExpression("^std::vector<.+>(( )?&)?$"),
986       SyntheticChildrenSP(new ScriptedSyntheticChildren(
987           stl_synth_flags,
988           "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
989   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
990       RegularExpression("^std::map<.+> >(( )?&)?$"),
991       SyntheticChildrenSP(new ScriptedSyntheticChildren(
992           stl_synth_flags,
993           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
994   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
995       RegularExpression("^std::deque<.+>(( )?&)?$"),
996       SyntheticChildrenSP(new ScriptedSyntheticChildren(
997           stl_deref_flags,
998           "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider")));
999   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1000       RegularExpression("^std::set<.+> >(( )?&)?$"),
1001       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1002           stl_deref_flags,
1003           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1004   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1005       RegularExpression("^std::multimap<.+> >(( )?&)?$"),
1006       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1007           stl_deref_flags,
1008           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1009   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1010       RegularExpression("^std::multiset<.+> >(( )?&)?$"),
1011       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1012           stl_deref_flags,
1013           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1014   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1015       RegularExpression("^std::unordered_(multi)?(map|set)<.+> >$"),
1016       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1017           stl_deref_flags,
1018           "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")));
1019   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1020       RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"),
1021       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1022           stl_deref_flags,
1023           "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
1024   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
1025       RegularExpression("^std::(__cxx11::)?forward_list<.+>(( )?&)?$"),
1026       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1027           stl_synth_flags,
1028           "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
1029 
1030   stl_summary_flags.SetDontShowChildren(false);
1031   stl_summary_flags.SetSkipPointers(false);
1032   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1033       RegularExpression("^std::bitset<.+>(( )?&)?$"),
1034       TypeSummaryImplSP(
1035           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1036   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1037       RegularExpression("^std::vector<.+>(( )?&)?$"),
1038       TypeSummaryImplSP(
1039           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1040   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1041       RegularExpression("^std::map<.+> >(( )?&)?$"),
1042       TypeSummaryImplSP(
1043           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1044   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1045       RegularExpression("^std::set<.+> >(( )?&)?$"),
1046       TypeSummaryImplSP(
1047           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1048   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1049       RegularExpression("^std::deque<.+>(( )?&)?$"),
1050       TypeSummaryImplSP(
1051           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1052   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1053       RegularExpression("^std::multimap<.+> >(( )?&)?$"),
1054       TypeSummaryImplSP(
1055           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1056   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1057       RegularExpression("^std::multiset<.+> >(( )?&)?$"),
1058       TypeSummaryImplSP(
1059           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1060   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1061       RegularExpression("^std::unordered_(multi)?(map|set)<.+> >$"),
1062       TypeSummaryImplSP(
1063           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1064   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1065       RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"),
1066       TypeSummaryImplSP(
1067           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
1068   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
1069       RegularExpression("^std::(__cxx11::)?forward_list<.+>(( )?&)?$"),
1070       TypeSummaryImplSP(
1071           new ScriptSummaryFormat(stl_summary_flags, "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")));
1072 
1073   AddCXXSynthetic(
1074       cpp_category_sp,
1075       lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator,
1076       "std::vector iterator synthetic children",
1077       ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
1078 
1079   AddCXXSynthetic(
1080       cpp_category_sp,
1081       lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator,
1082       "std::map iterator synthetic children",
1083       ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
1084 
1085   AddCXXSynthetic(
1086       cpp_category_sp,
1087       lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
1088       "std::unique_ptr synthetic children",
1089       ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
1090   AddCXXSynthetic(
1091       cpp_category_sp,
1092       lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
1093       "std::shared_ptr synthetic children",
1094       ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
1095   AddCXXSynthetic(
1096       cpp_category_sp,
1097       lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
1098       "std::weak_ptr synthetic children",
1099       ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
1100   AddCXXSynthetic(
1101       cpp_category_sp,
1102       lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
1103       "std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"),
1104       stl_synth_flags, true);
1105 
1106   AddCXXSynthetic(
1107       cpp_category_sp,
1108       lldb_private::formatters::LibStdcppBitsetSyntheticFrontEndCreator,
1109       "std::bitset synthetic child", ConstString("^std::bitset<.+>(( )?&)?$"),
1110       stl_deref_flags, true);
1111 
1112   AddCXXSynthetic(
1113       cpp_category_sp,
1114       lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator,
1115       "std::optional synthetic child",
1116       ConstString("^std::optional<.+>(( )?&)?$"), stl_deref_flags, true);
1117 
1118   AddCXXSummary(cpp_category_sp,
1119                 lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
1120                 "libstdc++ std::unique_ptr summary provider",
1121                 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_summary_flags,
1122                 true);
1123   AddCXXSummary(cpp_category_sp,
1124                 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
1125                 "libstdc++ std::shared_ptr summary provider",
1126                 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags,
1127                 true);
1128   AddCXXSummary(cpp_category_sp,
1129                 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
1130                 "libstdc++ std::weak_ptr summary provider",
1131                 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags,
1132                 true);
1133   AddCXXSummary(
1134       cpp_category_sp, lldb_private::formatters::GenericOptionalSummaryProvider,
1135       "libstd++ std::optional summary provider",
1136       ConstString("^std::optional<.+>(( )?&)?$"), stl_summary_flags, true);
1137 }
1138 
1139 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1140   if (!cpp_category_sp)
1141     return;
1142 
1143   TypeSummaryImpl::Flags string_flags;
1144   string_flags.SetCascades(true)
1145       .SetSkipPointers(true)
1146       .SetSkipReferences(false)
1147       .SetDontShowChildren(true)
1148       .SetDontShowValue(false)
1149       .SetShowMembersOneLiner(false)
1150       .SetHideItemNames(false);
1151 
1152   TypeSummaryImpl::Flags string_array_flags;
1153   string_array_flags.SetCascades(true)
1154       .SetSkipPointers(true)
1155       .SetSkipReferences(false)
1156       .SetDontShowChildren(true)
1157       .SetDontShowValue(true)
1158       .SetShowMembersOneLiner(false)
1159       .SetHideItemNames(false);
1160 
1161   AddCXXSummary(
1162       cpp_category_sp, lldb_private::formatters::Char8StringSummaryProvider,
1163       "char8_t * summary provider", ConstString("char8_t *"), string_flags);
1164   AddCXXSummary(cpp_category_sp,
1165                 lldb_private::formatters::Char8StringSummaryProvider,
1166                 "char8_t [] summary provider",
1167                 ConstString("char8_t ?\\[[0-9]+\\]"), string_array_flags, true);
1168 
1169   AddCXXSummary(
1170       cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
1171       "char16_t * summary provider", ConstString("char16_t *"), string_flags);
1172   AddCXXSummary(cpp_category_sp,
1173                 lldb_private::formatters::Char16StringSummaryProvider,
1174                 "char16_t [] summary provider",
1175                 ConstString("char16_t ?\\[[0-9]+\\]"), string_array_flags, true);
1176 
1177   AddCXXSummary(
1178       cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider,
1179       "char32_t * summary provider", ConstString("char32_t *"), string_flags);
1180   AddCXXSummary(cpp_category_sp,
1181                 lldb_private::formatters::Char32StringSummaryProvider,
1182                 "char32_t [] summary provider",
1183                 ConstString("char32_t ?\\[[0-9]+\\]"), string_array_flags, true);
1184 
1185   AddCXXSummary(
1186       cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider,
1187       "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
1188   AddCXXSummary(cpp_category_sp,
1189                 lldb_private::formatters::WCharStringSummaryProvider,
1190                 "wchar_t * summary provider",
1191                 ConstString("wchar_t ?\\[[0-9]+\\]"), string_array_flags, true);
1192 
1193   AddCXXSummary(
1194       cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
1195       "unichar * summary provider", ConstString("unichar *"), string_flags);
1196 
1197   TypeSummaryImpl::Flags widechar_flags;
1198   widechar_flags.SetDontShowValue(true)
1199       .SetSkipPointers(true)
1200       .SetSkipReferences(false)
1201       .SetCascades(true)
1202       .SetDontShowChildren(true)
1203       .SetHideItemNames(true)
1204       .SetShowMembersOneLiner(false);
1205 
1206   AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char8SummaryProvider,
1207                 "char8_t summary provider", ConstString("char8_t"),
1208                 widechar_flags);
1209   AddCXXSummary(
1210       cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
1211       "char16_t summary provider", ConstString("char16_t"), widechar_flags);
1212   AddCXXSummary(
1213       cpp_category_sp, lldb_private::formatters::Char32SummaryProvider,
1214       "char32_t summary provider", ConstString("char32_t"), widechar_flags);
1215   AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider,
1216                 "wchar_t summary provider", ConstString("wchar_t"),
1217                 widechar_flags);
1218 
1219   AddCXXSummary(
1220       cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
1221       "unichar summary provider", ConstString("unichar"), widechar_flags);
1222 }
1223 
1224 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() {
1225   class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger {
1226   public:
1227     CompilerType AdjustForInclusion(CompilerType &candidate) override {
1228       LanguageType lang_type(candidate.GetMinimumLanguage());
1229       if (!Language::LanguageIsC(lang_type) &&
1230           !Language::LanguageIsCPlusPlus(lang_type))
1231         return CompilerType();
1232       if (candidate.IsTypedefType())
1233         return candidate.GetTypedefedType();
1234       return candidate;
1235     }
1236   };
1237 
1238   return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
1239 }
1240 
1241 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
1242   static llvm::once_flag g_initialize;
1243   static TypeCategoryImplSP g_category;
1244 
1245   llvm::call_once(g_initialize, [this]() -> void {
1246     DataVisualization::Categories::GetCategory(ConstString(GetPluginName()),
1247                                                g_category);
1248     if (g_category) {
1249       LoadLibStdcppFormatters(g_category);
1250       LoadLibCxxFormatters(g_category);
1251       LoadSystemFormatters(g_category);
1252     }
1253   });
1254   return g_category;
1255 }
1256 
1257 HardcodedFormatters::HardcodedSummaryFinder
1258 CPlusPlusLanguage::GetHardcodedSummaries() {
1259   static llvm::once_flag g_initialize;
1260   static ConstString g_vectortypes("VectorTypes");
1261   static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
1262 
1263   llvm::call_once(g_initialize, []() -> void {
1264     g_formatters.push_back(
1265         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1266            FormatManager &) -> TypeSummaryImpl::SharedPointer {
1267           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1268               new CXXFunctionSummaryFormat(
1269                   TypeSummaryImpl::Flags(),
1270                   lldb_private::formatters::CXXFunctionPointerSummaryProvider,
1271                   "Function pointer summary provider"));
1272           if (valobj.GetCompilerType().IsFunctionPointerType()) {
1273             return formatter_sp;
1274           }
1275           return nullptr;
1276         });
1277     g_formatters.push_back(
1278         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1279            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1280           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1281               new CXXFunctionSummaryFormat(
1282                   TypeSummaryImpl::Flags()
1283                       .SetCascades(true)
1284                       .SetDontShowChildren(true)
1285                       .SetHideItemNames(true)
1286                       .SetShowMembersOneLiner(true)
1287                       .SetSkipPointers(true)
1288                       .SetSkipReferences(false),
1289                   lldb_private::formatters::VectorTypeSummaryProvider,
1290                   "vector_type pointer summary provider"));
1291           if (valobj.GetCompilerType().IsVectorType()) {
1292             if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1293               return formatter_sp;
1294           }
1295           return nullptr;
1296         });
1297     g_formatters.push_back(
1298         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1299            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1300           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1301               new CXXFunctionSummaryFormat(
1302                   TypeSummaryImpl::Flags()
1303                       .SetCascades(true)
1304                       .SetDontShowChildren(true)
1305                       .SetHideItemNames(true)
1306                       .SetShowMembersOneLiner(true)
1307                       .SetSkipPointers(true)
1308                       .SetSkipReferences(false),
1309                   lldb_private::formatters::BlockPointerSummaryProvider,
1310                   "block pointer summary provider"));
1311           if (valobj.GetCompilerType().IsBlockPointerType()) {
1312             return formatter_sp;
1313           }
1314           return nullptr;
1315         });
1316   });
1317 
1318   return g_formatters;
1319 }
1320 
1321 HardcodedFormatters::HardcodedSyntheticFinder
1322 CPlusPlusLanguage::GetHardcodedSynthetics() {
1323   static llvm::once_flag g_initialize;
1324   static ConstString g_vectortypes("VectorTypes");
1325   static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
1326 
1327   llvm::call_once(g_initialize, []() -> void {
1328     g_formatters.push_back([](lldb_private::ValueObject &valobj,
1329                               lldb::DynamicValueType, FormatManager &fmt_mgr)
1330                                -> SyntheticChildren::SharedPointer {
1331       static CXXSyntheticChildren::SharedPointer formatter_sp(
1332           new CXXSyntheticChildren(
1333               SyntheticChildren::Flags()
1334                   .SetCascades(true)
1335                   .SetSkipPointers(true)
1336                   .SetSkipReferences(true)
1337                   .SetNonCacheable(true),
1338               "vector_type synthetic children",
1339               lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
1340       if (valobj.GetCompilerType().IsVectorType()) {
1341         if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1342           return formatter_sp;
1343       }
1344       return nullptr;
1345     });
1346     g_formatters.push_back([](lldb_private::ValueObject &valobj,
1347                               lldb::DynamicValueType, FormatManager &fmt_mgr)
1348                                -> SyntheticChildren::SharedPointer {
1349       static CXXSyntheticChildren::SharedPointer formatter_sp(
1350           new CXXSyntheticChildren(
1351               SyntheticChildren::Flags()
1352                   .SetCascades(true)
1353                   .SetSkipPointers(true)
1354                   .SetSkipReferences(true)
1355                   .SetNonCacheable(true),
1356               "block pointer synthetic children",
1357               lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
1358       if (valobj.GetCompilerType().IsBlockPointerType()) {
1359         return formatter_sp;
1360       }
1361       return nullptr;
1362     });
1363   });
1364 
1365   return g_formatters;
1366 }
1367 
1368 bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) {
1369   if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) ||
1370       !valobj.IsPointerType())
1371     return false;
1372   bool canReadValue = true;
1373   bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
1374   return canReadValue && isZero;
1375 }
1376 
1377 bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
1378   const auto suffixes = {".cpp", ".cxx", ".c++", ".cc",  ".c",
1379                          ".h",   ".hh",  ".hpp", ".hxx", ".h++"};
1380   for (auto suffix : suffixes) {
1381     if (file_path.endswith_insensitive(suffix))
1382       return true;
1383   }
1384 
1385   // Check if we're in a STL path (where the files usually have no extension
1386   // that we could check for.
1387   return file_path.contains("/usr/include/c++/");
1388 }
1389