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