xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (revision b9c1b51e45b845debb76d8658edabca70ca56079)
1 //===-- CPlusPlusLanguage.cpp -----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "CPlusPlusLanguage.h"
11 
12 // C Includes
13 // C++ Includes
14 #include <cctype>
15 #include <cstring>
16 #include <functional>
17 #include <mutex>
18 
19 // Other libraries and framework includes
20 #include "llvm/ADT/StringRef.h"
21 
22 // Project includes
23 #include "lldb/Core/ConstString.h"
24 #include "lldb/Core/PluginManager.h"
25 #include "lldb/Core/RegularExpression.h"
26 #include "lldb/Core/UniqueCStringMap.h"
27 #include "lldb/DataFormatters/CXXFunctionPointer.h"
28 #include "lldb/DataFormatters/DataVisualization.h"
29 #include "lldb/DataFormatters/FormattersHelpers.h"
30 #include "lldb/DataFormatters/VectorType.h"
31 
32 #include "BlockPointer.h"
33 #include "CxxStringTypes.h"
34 #include "LibCxx.h"
35 #include "LibCxxAtomic.h"
36 #include "LibStdcpp.h"
37 
38 using namespace lldb;
39 using namespace lldb_private;
40 using namespace lldb_private::formatters;
41 
42 void CPlusPlusLanguage::Initialize() {
43   PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
44                                 CreateInstance);
45 }
46 
47 void CPlusPlusLanguage::Terminate() {
48   PluginManager::UnregisterPlugin(CreateInstance);
49 }
50 
51 lldb_private::ConstString CPlusPlusLanguage::GetPluginNameStatic() {
52   static ConstString g_name("cplusplus");
53   return g_name;
54 }
55 
56 //------------------------------------------------------------------
57 // PluginInterface protocol
58 //------------------------------------------------------------------
59 
60 lldb_private::ConstString CPlusPlusLanguage::GetPluginName() {
61   return GetPluginNameStatic();
62 }
63 
64 uint32_t CPlusPlusLanguage::GetPluginVersion() { return 1; }
65 
66 //------------------------------------------------------------------
67 // Static Functions
68 //------------------------------------------------------------------
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_type = eTypeInvalid;
83   m_parsed = false;
84   m_parse_error = false;
85 }
86 
87 bool ReverseFindMatchingChars(const llvm::StringRef &s,
88                               const llvm::StringRef &left_right_chars,
89                               size_t &left_pos, size_t &right_pos,
90                               size_t pos = llvm::StringRef::npos) {
91   assert(left_right_chars.size() == 2);
92   left_pos = llvm::StringRef::npos;
93   const char left_char = left_right_chars[0];
94   const char right_char = left_right_chars[1];
95   pos = s.find_last_of(left_right_chars, pos);
96   if (pos == llvm::StringRef::npos || s[pos] == left_char)
97     return false;
98   right_pos = pos;
99   uint32_t depth = 1;
100   while (pos > 0 && depth > 0) {
101     pos = s.find_last_of(left_right_chars, pos);
102     if (pos == llvm::StringRef::npos)
103       return false;
104     if (s[pos] == left_char) {
105       if (--depth == 0) {
106         left_pos = pos;
107         return left_pos < right_pos;
108       }
109     } else if (s[pos] == right_char) {
110       ++depth;
111     }
112   }
113   return false;
114 }
115 
116 static bool IsValidBasename(const llvm::StringRef &basename) {
117   // Check that the basename matches with the following regular expression or is
118   // an operator name:
119   // "^~?([A-Za-z_][A-Za-z_0-9]*)(<.*>)?$"
120   // We are using a hand written implementation because it is significantly more
121   // efficient then
122   // using the general purpose regular expression library.
123   size_t idx = 0;
124   if (basename.size() > 0 && basename[0] == '~')
125     idx = 1;
126 
127   if (basename.size() <= idx)
128     return false; // Empty string or "~"
129 
130   if (!std::isalpha(basename[idx]) && basename[idx] != '_')
131     return false; // First charater (after removing the possible '~'') isn't in
132                   // [A-Za-z_]
133 
134   // Read all characters matching [A-Za-z_0-9]
135   ++idx;
136   while (idx < basename.size()) {
137     if (!std::isalnum(basename[idx]) && basename[idx] != '_')
138       break;
139     ++idx;
140   }
141 
142   // We processed all characters. It is a vaild basename.
143   if (idx == basename.size())
144     return true;
145 
146   // Check for basename with template arguments
147   // TODO: Improve the quality of the validation with validating the template
148   // arguments
149   if (basename[idx] == '<' && basename.back() == '>')
150     return true;
151 
152   // Check if the basename is a vaild C++ operator name
153   if (!basename.startswith("operator"))
154     return false;
155 
156   static RegularExpression g_operator_regex("^(operator)( "
157                                             "?)([A-Za-z_][A-Za-z_0-9]*|\\(\\)|"
158                                             "\\[\\]|[\\^<>=!\\/"
159                                             "*+-]+)(<.*>)?(\\[\\])?$");
160   std::string basename_str(basename.str());
161   return g_operator_regex.Execute(basename_str.c_str(), nullptr);
162 }
163 
164 void CPlusPlusLanguage::MethodName::Parse() {
165   if (!m_parsed && m_full) {
166     //        ConstString mangled;
167     //        m_full.GetMangledCounterpart(mangled);
168     //        printf ("\n   parsing = '%s'\n", m_full.GetCString());
169     //        if (mangled)
170     //            printf ("   mangled = '%s'\n", mangled.GetCString());
171     m_parse_error = false;
172     m_parsed = true;
173     llvm::StringRef full(m_full.GetCString());
174 
175     size_t arg_start, arg_end;
176     llvm::StringRef parens("()", 2);
177     if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
178       m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
179       if (arg_end + 1 < full.size())
180         m_qualifiers = full.substr(arg_end + 1);
181       if (arg_start > 0) {
182         size_t basename_end = arg_start;
183         size_t context_start = 0;
184         size_t context_end = llvm::StringRef::npos;
185         if (basename_end > 0 && full[basename_end - 1] == '>') {
186           // TODO: handle template junk...
187           // Templated function
188           size_t template_start, template_end;
189           llvm::StringRef lt_gt("<>", 2);
190           if (ReverseFindMatchingChars(full, lt_gt, template_start,
191                                        template_end, basename_end)) {
192             // Check for templated functions that include return type like:
193             // 'void foo<Int>()'
194             context_start = full.rfind(' ', template_start);
195             if (context_start == llvm::StringRef::npos)
196               context_start = 0;
197             else
198               ++context_start;
199 
200             context_end = full.rfind(':', template_start);
201             if (context_end == llvm::StringRef::npos ||
202                 context_end < context_start)
203               context_end = context_start;
204           } else {
205             context_end = full.rfind(':', basename_end);
206           }
207         } else if (context_end == llvm::StringRef::npos) {
208           context_end = full.rfind(':', basename_end);
209         }
210 
211         if (context_end == llvm::StringRef::npos)
212           m_basename = full.substr(0, basename_end);
213         else {
214           if (context_start < context_end)
215             m_context =
216                 full.substr(context_start, context_end - 1 - context_start);
217           const size_t basename_begin = context_end + 1;
218           m_basename =
219               full.substr(basename_begin, basename_end - basename_begin);
220         }
221         m_type = eTypeUnknownMethod;
222       } else {
223         m_parse_error = true;
224         return;
225       }
226 
227       if (!IsValidBasename(m_basename)) {
228         // The C++ basename doesn't match our regular expressions so this can't
229         // be a valid C++ method, clear everything out and indicate an error
230         m_context = llvm::StringRef();
231         m_basename = llvm::StringRef();
232         m_arguments = llvm::StringRef();
233         m_qualifiers = llvm::StringRef();
234         m_parse_error = true;
235       }
236     } else {
237       m_parse_error = true;
238     }
239   }
240 }
241 
242 llvm::StringRef CPlusPlusLanguage::MethodName::GetBasename() {
243   if (!m_parsed)
244     Parse();
245   return m_basename;
246 }
247 
248 llvm::StringRef CPlusPlusLanguage::MethodName::GetContext() {
249   if (!m_parsed)
250     Parse();
251   return m_context;
252 }
253 
254 llvm::StringRef CPlusPlusLanguage::MethodName::GetArguments() {
255   if (!m_parsed)
256     Parse();
257   return m_arguments;
258 }
259 
260 llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
261   if (!m_parsed)
262     Parse();
263   return m_qualifiers;
264 }
265 
266 std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
267   if (!m_parsed)
268     Parse();
269   if (m_basename.empty() || m_context.empty())
270     return std::string();
271 
272   std::string res;
273   res += m_context;
274   res += "::";
275   res += m_basename;
276 
277   return res;
278 }
279 
280 bool CPlusPlusLanguage::IsCPPMangledName(const char *name) {
281   // FIXME, we should really run through all the known C++ Language plugins and
282   // ask each one if
283   // this is a C++ mangled name, but we can put that off till there is actually
284   // more than one
285   // we care about.
286 
287   return (name != nullptr && name[0] == '_' && name[1] == 'Z');
288 }
289 
290 bool CPlusPlusLanguage::ExtractContextAndIdentifier(
291     const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
292   static RegularExpression g_basename_regex(
293       "^(([A-Za-z_][A-Za-z_0-9]*::)*)(~?[A-Za-z_~][A-Za-z_0-9]*)$");
294   RegularExpression::Match match(4);
295   if (g_basename_regex.Execute(name, &match)) {
296     match.GetMatchAtIndex(name, 1, context);
297     match.GetMatchAtIndex(name, 3, identifier);
298     return true;
299   }
300   return false;
301 }
302 
303 class CPPRuntimeEquivalents {
304 public:
305   CPPRuntimeEquivalents() {
306     m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, "
307                               "std::allocator<char> >")
308                       .AsCString(),
309                   ConstString("basic_string<char>"));
310 
311     // these two (with a prefixed std::) occur when c++stdlib string class
312     // occurs as a template argument in some STL container
313     m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, "
314                               "std::allocator<char> >")
315                       .AsCString(),
316                   ConstString("std::basic_string<char>"));
317 
318     m_impl.Sort();
319   }
320 
321   void Add(ConstString &type_name, ConstString &type_equivalent) {
322     m_impl.Insert(type_name.AsCString(), type_equivalent);
323   }
324 
325   uint32_t FindExactMatches(ConstString &type_name,
326                             std::vector<ConstString> &equivalents) {
327     uint32_t count = 0;
328 
329     for (ImplData match = m_impl.FindFirstValueForName(type_name.AsCString());
330          match != nullptr; match = m_impl.FindNextValueForName(match)) {
331       equivalents.push_back(match->value);
332       count++;
333     }
334 
335     return count;
336   }
337 
338   // partial matches can occur when a name with equivalents is a template
339   // argument.
340   // e.g. we may have "class Foo" be a match for "struct Bar". if we have a
341   // typename
342   // such as "class Templatized<class Foo, Anything>" we want this to be
343   // replaced with
344   // "class Templatized<struct Bar, Anything>". Since partial matching is time
345   // consuming
346   // once we get a partial match, we add it to the exact matches list for faster
347   // retrieval
348   uint32_t FindPartialMatches(ConstString &type_name,
349                               std::vector<ConstString> &equivalents) {
350     uint32_t count = 0;
351 
352     const char *type_name_cstr = type_name.AsCString();
353 
354     size_t items_count = m_impl.GetSize();
355 
356     for (size_t item = 0; item < items_count; item++) {
357       const char *key_cstr = m_impl.GetCStringAtIndex(item);
358       if (strstr(type_name_cstr, key_cstr)) {
359         count += AppendReplacements(type_name_cstr, key_cstr, equivalents);
360       }
361     }
362 
363     return count;
364   }
365 
366 private:
367   std::string &replace(std::string &target, std::string &pattern,
368                        std::string &with) {
369     size_t pos;
370     size_t pattern_len = pattern.size();
371 
372     while ((pos = target.find(pattern)) != std::string::npos)
373       target.replace(pos, pattern_len, with);
374 
375     return target;
376   }
377 
378   uint32_t AppendReplacements(const char *original, const char *matching_key,
379                               std::vector<ConstString> &equivalents) {
380     std::string matching_key_str(matching_key);
381     ConstString original_const(original);
382 
383     uint32_t count = 0;
384 
385     for (ImplData match = m_impl.FindFirstValueForName(matching_key);
386          match != nullptr; match = m_impl.FindNextValueForName(match)) {
387       std::string target(original);
388       std::string equiv_class(match->value.AsCString());
389 
390       replace(target, matching_key_str, equiv_class);
391 
392       ConstString target_const(target.c_str());
393 
394 // you will most probably want to leave this off since it might make this map
395 // grow indefinitely
396 #ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW
397       Add(original_const, target_const);
398 #endif
399       equivalents.push_back(target_const);
400 
401       count++;
402     }
403 
404     return count;
405   }
406 
407   typedef UniqueCStringMap<ConstString> Impl;
408   typedef const Impl::Entry *ImplData;
409   Impl m_impl;
410 };
411 
412 static CPPRuntimeEquivalents &GetEquivalentsMap() {
413   static CPPRuntimeEquivalents g_equivalents_map;
414   return g_equivalents_map;
415 }
416 
417 uint32_t
418 CPlusPlusLanguage::FindEquivalentNames(ConstString type_name,
419                                        std::vector<ConstString> &equivalents) {
420   uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents);
421 
422   bool might_have_partials =
423       (count == 0) // if we have a full name match just use it
424       && (strchr(type_name.AsCString(), '<') !=
425               nullptr // we should only have partial matches when templates are
426                       // involved, check that we have
427           && strchr(type_name.AsCString(), '>') != nullptr); // angle brackets
428                                                              // in the type_name
429                                                              // before trying to
430                                                              // scan for partial
431                                                              // matches
432 
433   if (might_have_partials)
434     count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents);
435 
436   return count;
437 }
438 
439 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
440   if (!cpp_category_sp)
441     return;
442 
443   TypeSummaryImpl::Flags stl_summary_flags;
444   stl_summary_flags.SetCascades(true)
445       .SetSkipPointers(false)
446       .SetSkipReferences(false)
447       .SetDontShowChildren(true)
448       .SetDontShowValue(true)
449       .SetShowMembersOneLiner(false)
450       .SetHideItemNames(false);
451 
452 #ifndef LLDB_DISABLE_PYTHON
453   lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat(
454       stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider,
455       "std::string summary provider"));
456   lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat(
457       stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider,
458       "std::wstring summary provider"));
459 
460   cpp_category_sp->GetTypeSummariesContainer()->Add(
461       ConstString("std::__1::string"), std_string_summary_sp);
462   cpp_category_sp->GetTypeSummariesContainer()->Add(
463       ConstString("std::__ndk1::string"), std_string_summary_sp);
464   cpp_category_sp->GetTypeSummariesContainer()->Add(
465       ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, "
466                   "std::__1::allocator<char> >"),
467       std_string_summary_sp);
468   cpp_category_sp->GetTypeSummariesContainer()->Add(
469       ConstString("std::__ndk1::basic_string<char, "
470                   "std::__ndk1::char_traits<char>, "
471                   "std::__ndk1::allocator<char> >"),
472       std_string_summary_sp);
473 
474   cpp_category_sp->GetTypeSummariesContainer()->Add(
475       ConstString("std::__1::wstring"), std_wstring_summary_sp);
476   cpp_category_sp->GetTypeSummariesContainer()->Add(
477       ConstString("std::__ndk1::wstring"), std_wstring_summary_sp);
478   cpp_category_sp->GetTypeSummariesContainer()->Add(
479       ConstString("std::__1::basic_string<wchar_t, "
480                   "std::__1::char_traits<wchar_t>, "
481                   "std::__1::allocator<wchar_t> >"),
482       std_wstring_summary_sp);
483   cpp_category_sp->GetTypeSummariesContainer()->Add(
484       ConstString("std::__ndk1::basic_string<wchar_t, "
485                   "std::__ndk1::char_traits<wchar_t>, "
486                   "std::__ndk1::allocator<wchar_t> >"),
487       std_wstring_summary_sp);
488 
489   SyntheticChildren::Flags stl_synth_flags;
490   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
491       false);
492 
493   AddCXXSynthetic(
494       cpp_category_sp,
495       lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator,
496       "libc++ std::vector<bool> synthetic children",
497       ConstString(
498           "^std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >$"),
499       stl_synth_flags, true);
500   AddCXXSynthetic(
501       cpp_category_sp,
502       lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
503       "libc++ std::vector synthetic children",
504       ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_synth_flags,
505       true);
506   AddCXXSynthetic(
507       cpp_category_sp,
508       lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator,
509       "libc++ std::list synthetic children",
510       ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), stl_synth_flags, true);
511   AddCXXSynthetic(
512       cpp_category_sp,
513       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
514       "libc++ std::map synthetic children",
515       ConstString("^std::__(ndk)?1::map<.+> >(( )?&)?$"), stl_synth_flags,
516       true);
517   AddCXXSynthetic(
518       cpp_category_sp,
519       lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator,
520       "libc++ std::vector<bool> synthetic children",
521       ConstString("std::__(ndk)?1::vector<std::__(ndk)?1::allocator<bool> >"),
522       stl_synth_flags);
523   AddCXXSynthetic(
524       cpp_category_sp,
525       lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator,
526       "libc++ std::vector<bool> synthetic children",
527       ConstString(
528           "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"),
529       stl_synth_flags);
530   AddCXXSynthetic(
531       cpp_category_sp,
532       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
533       "libc++ std::set synthetic children",
534       ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_synth_flags,
535       true);
536   AddCXXSynthetic(
537       cpp_category_sp,
538       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
539       "libc++ std::multiset synthetic children",
540       ConstString("^std::__(ndk)?1::multiset<.+> >(( )?&)?$"), stl_synth_flags,
541       true);
542   AddCXXSynthetic(
543       cpp_category_sp,
544       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
545       "libc++ std::multimap synthetic children",
546       ConstString("^std::__(ndk)?1::multimap<.+> >(( )?&)?$"), stl_synth_flags,
547       true);
548   AddCXXSynthetic(
549       cpp_category_sp,
550       lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator,
551       "libc++ std::unordered containers synthetic children",
552       ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"),
553       stl_synth_flags, true);
554   AddCXXSynthetic(
555       cpp_category_sp,
556       lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
557       "libc++ std::initializer_list synthetic children",
558       ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags,
559       true);
560   AddCXXSynthetic(
561       cpp_category_sp,
562       lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
563       "libc++ std::atomic synthetic children",
564       ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_synth_flags, true);
565 
566   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
567       RegularExpressionSP(
568           new RegularExpression("^(std::__(ndk)?1::)deque<.+>(( )?&)?$")),
569       SyntheticChildrenSP(new ScriptedSyntheticChildren(
570           stl_synth_flags,
571           "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
572 
573   AddCXXSynthetic(
574       cpp_category_sp,
575       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
576       "shared_ptr synthetic children",
577       ConstString("^(std::__(ndk)?1::)shared_ptr<.+>(( )?&)?$"),
578       stl_synth_flags, true);
579   AddCXXSynthetic(
580       cpp_category_sp,
581       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
582       "weak_ptr synthetic children",
583       ConstString("^(std::__(ndk)?1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags,
584       true);
585 
586   stl_summary_flags.SetDontShowChildren(false);
587   stl_summary_flags.SetSkipPointers(false);
588   AddCXXSummary(
589       cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
590       "libc++ std::vector<bool> summary provider",
591       ConstString(
592           "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"),
593       stl_summary_flags, true);
594   AddCXXSummary(cpp_category_sp,
595                 lldb_private::formatters::LibcxxContainerSummaryProvider,
596                 "libc++ std::vector summary provider",
597                 ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"),
598                 stl_summary_flags, true);
599   AddCXXSummary(cpp_category_sp,
600                 lldb_private::formatters::LibcxxContainerSummaryProvider,
601                 "libc++ std::list summary provider",
602                 ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"),
603                 stl_summary_flags, true);
604   AddCXXSummary(cpp_category_sp,
605                 lldb_private::formatters::LibcxxContainerSummaryProvider,
606                 "libc++ std::map summary provider",
607                 ConstString("^std::__(ndk)?1::map<.+>(( )?&)?$"),
608                 stl_summary_flags, true);
609   AddCXXSummary(cpp_category_sp,
610                 lldb_private::formatters::LibcxxContainerSummaryProvider,
611                 "libc++ std::deque summary provider",
612                 ConstString("^std::__(ndk)?1::deque<.+>(( )?&)?$"),
613                 stl_summary_flags, true);
614   AddCXXSummary(cpp_category_sp,
615                 lldb_private::formatters::LibcxxContainerSummaryProvider,
616                 "libc++ std::set summary provider",
617                 ConstString("^std::__(ndk)?1::set<.+>(( )?&)?$"),
618                 stl_summary_flags, true);
619   AddCXXSummary(cpp_category_sp,
620                 lldb_private::formatters::LibcxxContainerSummaryProvider,
621                 "libc++ std::multiset summary provider",
622                 ConstString("^std::__(ndk)?1::multiset<.+>(( )?&)?$"),
623                 stl_summary_flags, true);
624   AddCXXSummary(cpp_category_sp,
625                 lldb_private::formatters::LibcxxContainerSummaryProvider,
626                 "libc++ std::multimap summary provider",
627                 ConstString("^std::__(ndk)?1::multimap<.+>(( )?&)?$"),
628                 stl_summary_flags, true);
629   AddCXXSummary(
630       cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
631       "libc++ std::unordered containers summary provider",
632       ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"),
633       stl_summary_flags, true);
634   AddCXXSummary(
635       cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider,
636       "libc++ std::atomic summary provider",
637       ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_summary_flags, true);
638 
639   stl_summary_flags.SetSkipPointers(true);
640 
641   AddCXXSummary(cpp_category_sp,
642                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
643                 "libc++ std::shared_ptr summary provider",
644                 ConstString("^std::__(ndk)?1::shared_ptr<.+>(( )?&)?$"),
645                 stl_summary_flags, true);
646   AddCXXSummary(cpp_category_sp,
647                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
648                 "libc++ std::weak_ptr summary provider",
649                 ConstString("^std::__(ndk)?1::weak_ptr<.+>(( )?&)?$"),
650                 stl_summary_flags, true);
651 
652   AddCXXSynthetic(
653       cpp_category_sp,
654       lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator,
655       "std::vector iterator synthetic children",
656       ConstString("^std::__(ndk)?1::__wrap_iter<.+>$"), stl_synth_flags, true);
657 
658   AddCXXSummary(
659       cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
660       "libc++ std::vector<bool> summary provider",
661       ConstString(
662           "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"),
663       stl_summary_flags);
664   AddCXXSynthetic(
665       cpp_category_sp,
666       lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
667       "std::map iterator synthetic children",
668       ConstString("^std::__(ndk)?1::__map_iterator<.+>$"), stl_synth_flags,
669       true);
670 
671   AddCXXSynthetic(
672       cpp_category_sp, lldb_private::formatters::LibcxxFunctionFrontEndCreator,
673       "std::function synthetic value provider",
674       ConstString("^std::__1::function<.+>$"), stl_synth_flags, true);
675 #endif
676 }
677 
678 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
679   if (!cpp_category_sp)
680     return;
681 
682   TypeSummaryImpl::Flags stl_summary_flags;
683   stl_summary_flags.SetCascades(true)
684       .SetSkipPointers(false)
685       .SetSkipReferences(false)
686       .SetDontShowChildren(true)
687       .SetDontShowValue(true)
688       .SetShowMembersOneLiner(false)
689       .SetHideItemNames(false);
690 
691   lldb::TypeSummaryImplSP std_string_summary_sp(
692       new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}"));
693 
694   lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(
695       stl_summary_flags, LibStdcppStringSummaryProvider,
696       "libstdc++ c++11 std::string summary provider"));
697   lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(
698       stl_summary_flags, LibStdcppWStringSummaryProvider,
699       "libstdc++ c++11 std::wstring summary provider"));
700 
701   cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
702                                                     std_string_summary_sp);
703   cpp_category_sp->GetTypeSummariesContainer()->Add(
704       ConstString("std::basic_string<char>"), std_string_summary_sp);
705   cpp_category_sp->GetTypeSummariesContainer()->Add(
706       ConstString("std::basic_string<char,std::char_traits<char>,std::"
707                   "allocator<char> >"),
708       std_string_summary_sp);
709   cpp_category_sp->GetTypeSummariesContainer()->Add(
710       ConstString("std::basic_string<char, std::char_traits<char>, "
711                   "std::allocator<char> >"),
712       std_string_summary_sp);
713 
714   cpp_category_sp->GetTypeSummariesContainer()->Add(
715       ConstString("std::__cxx11::string"), cxx11_string_summary_sp);
716   cpp_category_sp->GetTypeSummariesContainer()->Add(
717       ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, "
718                   "std::allocator<char> >"),
719       cxx11_string_summary_sp);
720 
721   // making sure we force-pick the summary for printing wstring (_M_p is a
722   // wchar_t*)
723   lldb::TypeSummaryImplSP std_wstring_summary_sp(
724       new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
725 
726   cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"),
727                                                     std_wstring_summary_sp);
728   cpp_category_sp->GetTypeSummariesContainer()->Add(
729       ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp);
730   cpp_category_sp->GetTypeSummariesContainer()->Add(
731       ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::"
732                   "allocator<wchar_t> >"),
733       std_wstring_summary_sp);
734   cpp_category_sp->GetTypeSummariesContainer()->Add(
735       ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, "
736                   "std::allocator<wchar_t> >"),
737       std_wstring_summary_sp);
738 
739   cpp_category_sp->GetTypeSummariesContainer()->Add(
740       ConstString("std::__cxx11::wstring"), cxx11_wstring_summary_sp);
741   cpp_category_sp->GetTypeSummariesContainer()->Add(
742       ConstString("std::__cxx11::basic_string<wchar_t, "
743                   "std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
744       cxx11_wstring_summary_sp);
745 
746 #ifndef LLDB_DISABLE_PYTHON
747 
748   SyntheticChildren::Flags stl_synth_flags;
749   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
750       false);
751 
752   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
753       RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
754       SyntheticChildrenSP(new ScriptedSyntheticChildren(
755           stl_synth_flags,
756           "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
757   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
758       RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
759       SyntheticChildrenSP(new ScriptedSyntheticChildren(
760           stl_synth_flags,
761           "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider")));
762   cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
763       RegularExpressionSP(
764           new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
765       SyntheticChildrenSP(new ScriptedSyntheticChildren(
766           stl_synth_flags,
767           "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
768   stl_summary_flags.SetDontShowChildren(false);
769   stl_summary_flags.SetSkipPointers(true);
770   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
771       RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
772       TypeSummaryImplSP(
773           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
774   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
775       RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
776       TypeSummaryImplSP(
777           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
778   cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
779       RegularExpressionSP(
780           new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
781       TypeSummaryImplSP(
782           new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
783 
784   AddCXXSynthetic(
785       cpp_category_sp,
786       lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator,
787       "std::vector iterator synthetic children",
788       ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
789 
790   AddCXXSynthetic(
791       cpp_category_sp,
792       lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator,
793       "std::map iterator synthetic children",
794       ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
795 
796   AddCXXSynthetic(
797       cpp_category_sp,
798       lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
799       "std::shared_ptr synthetic children",
800       ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
801   AddCXXSynthetic(
802       cpp_category_sp,
803       lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
804       "std::weak_ptr synthetic children",
805       ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
806 
807   AddCXXSummary(cpp_category_sp,
808                 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
809                 "libstdc++ std::shared_ptr summary provider",
810                 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags,
811                 true);
812   AddCXXSummary(cpp_category_sp,
813                 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
814                 "libstdc++ std::weak_ptr summary provider",
815                 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags,
816                 true);
817 #endif
818 }
819 
820 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
821   if (!cpp_category_sp)
822     return;
823 
824   TypeSummaryImpl::Flags string_flags;
825   string_flags.SetCascades(true)
826       .SetSkipPointers(true)
827       .SetSkipReferences(false)
828       .SetDontShowChildren(true)
829       .SetDontShowValue(false)
830       .SetShowMembersOneLiner(false)
831       .SetHideItemNames(false);
832 
833   TypeSummaryImpl::Flags string_array_flags;
834   string_array_flags.SetCascades(true)
835       .SetSkipPointers(true)
836       .SetSkipReferences(false)
837       .SetDontShowChildren(true)
838       .SetDontShowValue(true)
839       .SetShowMembersOneLiner(false)
840       .SetHideItemNames(false);
841 
842 #ifndef LLDB_DISABLE_PYTHON
843   // FIXME because of a bug in the FormattersContainer we need to add a summary
844   // for both X* and const X* (<rdar://problem/12717717>)
845   AddCXXSummary(
846       cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
847       "char16_t * summary provider", ConstString("char16_t *"), string_flags);
848   AddCXXSummary(cpp_category_sp,
849                 lldb_private::formatters::Char16StringSummaryProvider,
850                 "char16_t [] summary provider",
851                 ConstString("char16_t \\[[0-9]+\\]"), string_array_flags, true);
852 
853   AddCXXSummary(
854       cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider,
855       "char32_t * summary provider", ConstString("char32_t *"), string_flags);
856   AddCXXSummary(cpp_category_sp,
857                 lldb_private::formatters::Char32StringSummaryProvider,
858                 "char32_t [] summary provider",
859                 ConstString("char32_t \\[[0-9]+\\]"), string_array_flags, true);
860 
861   AddCXXSummary(
862       cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider,
863       "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
864   AddCXXSummary(cpp_category_sp,
865                 lldb_private::formatters::WCharStringSummaryProvider,
866                 "wchar_t * summary provider",
867                 ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true);
868 
869   AddCXXSummary(
870       cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider,
871       "unichar * summary provider", ConstString("unichar *"), string_flags);
872 
873   TypeSummaryImpl::Flags widechar_flags;
874   widechar_flags.SetDontShowValue(true)
875       .SetSkipPointers(true)
876       .SetSkipReferences(false)
877       .SetCascades(true)
878       .SetDontShowChildren(true)
879       .SetHideItemNames(true)
880       .SetShowMembersOneLiner(false);
881 
882   AddCXXSummary(
883       cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
884       "char16_t summary provider", ConstString("char16_t"), widechar_flags);
885   AddCXXSummary(
886       cpp_category_sp, lldb_private::formatters::Char32SummaryProvider,
887       "char32_t summary provider", ConstString("char32_t"), widechar_flags);
888   AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider,
889                 "wchar_t summary provider", ConstString("wchar_t"),
890                 widechar_flags);
891 
892   AddCXXSummary(
893       cpp_category_sp, lldb_private::formatters::Char16SummaryProvider,
894       "unichar summary provider", ConstString("unichar"), widechar_flags);
895 #endif
896 }
897 
898 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
899   static std::once_flag g_initialize;
900   static TypeCategoryImplSP g_category;
901 
902   std::call_once(g_initialize, [this]() -> void {
903     DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
904     if (g_category) {
905       LoadLibCxxFormatters(g_category);
906       LoadLibStdcppFormatters(g_category);
907       LoadSystemFormatters(g_category);
908     }
909   });
910   return g_category;
911 }
912 
913 HardcodedFormatters::HardcodedSummaryFinder
914 CPlusPlusLanguage::GetHardcodedSummaries() {
915   static std::once_flag g_initialize;
916   static ConstString g_vectortypes("VectorTypes");
917   static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
918 
919   std::call_once(g_initialize, []() -> void {
920     g_formatters.push_back(
921         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
922            FormatManager &) -> TypeSummaryImpl::SharedPointer {
923           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
924               new CXXFunctionSummaryFormat(
925                   TypeSummaryImpl::Flags(),
926                   lldb_private::formatters::CXXFunctionPointerSummaryProvider,
927                   "Function pointer summary provider"));
928           if (valobj.GetCompilerType().IsFunctionPointerType()) {
929             return formatter_sp;
930           }
931           return nullptr;
932         });
933     g_formatters.push_back(
934         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
935            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
936           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
937               new CXXFunctionSummaryFormat(
938                   TypeSummaryImpl::Flags()
939                       .SetCascades(true)
940                       .SetDontShowChildren(true)
941                       .SetHideItemNames(true)
942                       .SetShowMembersOneLiner(true)
943                       .SetSkipPointers(true)
944                       .SetSkipReferences(false),
945                   lldb_private::formatters::VectorTypeSummaryProvider,
946                   "vector_type pointer summary provider"));
947           if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) {
948             if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
949               return formatter_sp;
950           }
951           return nullptr;
952         });
953     g_formatters.push_back(
954         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
955            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
956           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
957               new CXXFunctionSummaryFormat(
958                   TypeSummaryImpl::Flags()
959                       .SetCascades(true)
960                       .SetDontShowChildren(true)
961                       .SetHideItemNames(true)
962                       .SetShowMembersOneLiner(true)
963                       .SetSkipPointers(true)
964                       .SetSkipReferences(false),
965                   lldb_private::formatters::BlockPointerSummaryProvider,
966                   "block pointer summary provider"));
967           if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) {
968             return formatter_sp;
969           }
970           return nullptr;
971         });
972   });
973 
974   return g_formatters;
975 }
976 
977 HardcodedFormatters::HardcodedSyntheticFinder
978 CPlusPlusLanguage::GetHardcodedSynthetics() {
979   static std::once_flag g_initialize;
980   static ConstString g_vectortypes("VectorTypes");
981   static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
982 
983   std::call_once(g_initialize, []() -> void {
984     g_formatters.push_back([](lldb_private::ValueObject &valobj,
985                               lldb::DynamicValueType,
986                               FormatManager &
987                                   fmt_mgr) -> SyntheticChildren::SharedPointer {
988       static CXXSyntheticChildren::SharedPointer formatter_sp(
989           new CXXSyntheticChildren(
990               SyntheticChildren::Flags()
991                   .SetCascades(true)
992                   .SetSkipPointers(true)
993                   .SetSkipReferences(true)
994                   .SetNonCacheable(true),
995               "vector_type synthetic children",
996               lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
997       if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) {
998         if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
999           return formatter_sp;
1000       }
1001       return nullptr;
1002     });
1003     g_formatters.push_back([](lldb_private::ValueObject &valobj,
1004                               lldb::DynamicValueType,
1005                               FormatManager &
1006                                   fmt_mgr) -> SyntheticChildren::SharedPointer {
1007       static CXXSyntheticChildren::SharedPointer formatter_sp(
1008           new CXXSyntheticChildren(
1009               SyntheticChildren::Flags()
1010                   .SetCascades(true)
1011                   .SetSkipPointers(true)
1012                   .SetSkipReferences(true)
1013                   .SetNonCacheable(true),
1014               "block pointer synthetic children",
1015               lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
1016       if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) {
1017         return formatter_sp;
1018       }
1019       return nullptr;
1020     });
1021 
1022   });
1023 
1024   return g_formatters;
1025 }
1026