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