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