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