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