xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (revision 1b54baef15607b1c521feb3380688f46d59e3ee5)
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                         else
224                             ++context_start;
225 
226                         context_end = full.rfind(':', template_start);
227                         if (context_end == llvm::StringRef::npos || context_end < context_start)
228                             context_end = context_start;
229                     }
230                     else
231                     {
232                         context_end = full.rfind(':', basename_end);
233                     }
234                 }
235                 else if (context_end == llvm::StringRef::npos)
236                 {
237                     context_end = full.rfind(':', basename_end);
238                 }
239 
240                 if (context_end == llvm::StringRef::npos)
241                     m_basename = full.substr(0, basename_end);
242                 else
243                 {
244                     if (context_start < context_end)
245                         m_context = full.substr(context_start, context_end - 1 - context_start);
246                     const size_t basename_begin = context_end + 1;
247                     m_basename = full.substr(basename_begin, basename_end - basename_begin);
248                 }
249                 m_type = eTypeUnknownMethod;
250             }
251             else
252             {
253                 m_parse_error = true;
254                 return;
255             }
256 
257             if (!IsValidBasename(m_basename))
258             {
259                 // The C++ basename doesn't match our regular expressions so this can't
260                 // be a valid C++ method, clear everything out and indicate an error
261                 m_context = llvm::StringRef();
262                 m_basename = llvm::StringRef();
263                 m_arguments = llvm::StringRef();
264                 m_qualifiers = llvm::StringRef();
265                 m_parse_error = true;
266             }
267         }
268         else
269         {
270             m_parse_error = true;
271         }
272     }
273 }
274 
275 llvm::StringRef
276 CPlusPlusLanguage::MethodName::GetBasename ()
277 {
278     if (!m_parsed)
279         Parse();
280     return m_basename;
281 }
282 
283 llvm::StringRef
284 CPlusPlusLanguage::MethodName::GetContext ()
285 {
286     if (!m_parsed)
287         Parse();
288     return m_context;
289 }
290 
291 llvm::StringRef
292 CPlusPlusLanguage::MethodName::GetArguments ()
293 {
294     if (!m_parsed)
295         Parse();
296     return m_arguments;
297 }
298 
299 llvm::StringRef
300 CPlusPlusLanguage::MethodName::GetQualifiers ()
301 {
302     if (!m_parsed)
303         Parse();
304     return m_qualifiers;
305 }
306 
307 std::string
308 CPlusPlusLanguage::MethodName::GetScopeQualifiedName ()
309 {
310     if (!m_parsed)
311         Parse();
312     if (m_basename.empty() || m_context.empty())
313         return std::string();
314 
315     std::string res;
316     res += m_context;
317     res += "::";
318     res += m_basename;
319 
320     return res;
321 }
322 
323 bool
324 CPlusPlusLanguage::IsCPPMangledName (const char *name)
325 {
326     // FIXME, we should really run through all the known C++ Language plugins and ask each one if
327     // this is a C++ mangled name, but we can put that off till there is actually more than one
328     // we care about.
329 
330     return (name != nullptr && name[0] == '_' && name[1] == 'Z');
331 }
332 
333 bool
334 CPlusPlusLanguage::ExtractContextAndIdentifier (const char *name, llvm::StringRef &context, llvm::StringRef &identifier)
335 {
336     static RegularExpression g_basename_regex("^(([A-Za-z_][A-Za-z_0-9]*::)*)(~?[A-Za-z_~][A-Za-z_0-9]*)$");
337     RegularExpression::Match match(4);
338     if (g_basename_regex.Execute (name, &match))
339     {
340         match.GetMatchAtIndex(name, 1, context);
341         match.GetMatchAtIndex(name, 3, identifier);
342         return true;
343     }
344     return false;
345 }
346 
347 class CPPRuntimeEquivalents
348 {
349 public:
350     CPPRuntimeEquivalents ()
351     {
352         m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("basic_string<char>"));
353 
354         // these two (with a prefixed std::) occur when c++stdlib string class occurs as a template argument in some STL container
355         m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("std::basic_string<char>"));
356 
357         m_impl.Sort();
358     }
359 
360     void
361     Add (ConstString& type_name,
362          ConstString& type_equivalent)
363     {
364         m_impl.Insert(type_name.AsCString(), type_equivalent);
365     }
366 
367     uint32_t
368     FindExactMatches (ConstString& type_name,
369                       std::vector<ConstString>& equivalents)
370     {
371         uint32_t count = 0;
372 
373         for (ImplData match = m_impl.FindFirstValueForName(type_name.AsCString());
374              match != nullptr;
375              match = m_impl.FindNextValueForName(match))
376         {
377             equivalents.push_back(match->value);
378             count++;
379         }
380 
381         return count;
382     }
383 
384     // partial matches can occur when a name with equivalents is a template argument.
385     // e.g. we may have "class Foo" be a match for "struct Bar". if we have a typename
386     // such as "class Templatized<class Foo, Anything>" we want this to be replaced with
387     // "class Templatized<struct Bar, Anything>". Since partial matching is time consuming
388     // once we get a partial match, we add it to the exact matches list for faster retrieval
389     uint32_t
390     FindPartialMatches (ConstString& type_name,
391                         std::vector<ConstString>& equivalents)
392     {
393         uint32_t count = 0;
394 
395         const char* type_name_cstr = type_name.AsCString();
396 
397         size_t items_count = m_impl.GetSize();
398 
399         for (size_t item = 0; item < items_count; item++)
400         {
401             const char* key_cstr = m_impl.GetCStringAtIndex(item);
402             if ( strstr(type_name_cstr,key_cstr) )
403             {
404                 count += AppendReplacements(type_name_cstr,
405                                             key_cstr,
406                                             equivalents);
407             }
408         }
409 
410         return count;
411     }
412 
413 private:
414     std::string& replace (std::string& target,
415                           std::string& pattern,
416                           std::string& with)
417     {
418         size_t pos;
419         size_t pattern_len = pattern.size();
420 
421         while ( (pos = target.find(pattern)) != std::string::npos )
422             target.replace(pos, pattern_len, with);
423 
424         return target;
425     }
426 
427     uint32_t
428     AppendReplacements (const char* original,
429                         const char *matching_key,
430                         std::vector<ConstString>& equivalents)
431     {
432         std::string matching_key_str(matching_key);
433         ConstString original_const(original);
434 
435         uint32_t count = 0;
436 
437         for (ImplData match = m_impl.FindFirstValueForName(matching_key);
438              match != nullptr;
439              match = m_impl.FindNextValueForName(match))
440         {
441             std::string target(original);
442             std::string equiv_class(match->value.AsCString());
443 
444             replace (target, matching_key_str, equiv_class);
445 
446             ConstString target_const(target.c_str());
447 
448 // you will most probably want to leave this off since it might make this map grow indefinitely
449 #ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW
450             Add(original_const, target_const);
451 #endif
452             equivalents.push_back(target_const);
453 
454             count++;
455         }
456 
457         return count;
458     }
459 
460     typedef UniqueCStringMap<ConstString> Impl;
461     typedef const Impl::Entry* ImplData;
462     Impl m_impl;
463 };
464 
465 static CPPRuntimeEquivalents&
466 GetEquivalentsMap ()
467 {
468     static CPPRuntimeEquivalents g_equivalents_map;
469     return g_equivalents_map;
470 }
471 
472 uint32_t
473 CPlusPlusLanguage::FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents)
474 {
475     uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents);
476 
477     bool might_have_partials=
478         ( count == 0 )  // if we have a full name match just use it
479         && (strchr(type_name.AsCString(), '<') != nullptr  // we should only have partial matches when templates are involved, check that we have
480             && strchr(type_name.AsCString(), '>') != nullptr); // angle brackets in the type_name before trying to scan for partial matches
481 
482     if ( might_have_partials )
483         count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents);
484 
485     return count;
486 }
487 
488 static void
489 LoadLibCxxFormatters (lldb::TypeCategoryImplSP cpp_category_sp)
490 {
491     if (!cpp_category_sp)
492         return;
493 
494     TypeSummaryImpl::Flags stl_summary_flags;
495     stl_summary_flags.SetCascades(true)
496     .SetSkipPointers(false)
497     .SetSkipReferences(false)
498     .SetDontShowChildren(true)
499     .SetDontShowValue(true)
500     .SetShowMembersOneLiner(false)
501     .SetHideItemNames(false);
502 
503 #ifndef LLDB_DISABLE_PYTHON
504     lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider, "std::string summary provider"));
505     lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, "std::wstring summary provider"));
506 
507     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::string"),
508                                                          std_string_summary_sp);
509     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__ndk1::string"),
510                                                          std_string_summary_sp);
511     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"),
512                                                          std_string_summary_sp);
513     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >"),
514                                                          std_string_summary_sp);
515 
516     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::wstring"),
517                                                          std_wstring_summary_sp);
518     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__ndk1::wstring"),
519                                                          std_wstring_summary_sp);
520     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"),
521                                                          std_wstring_summary_sp);
522     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__ndk1::basic_string<wchar_t, std::__ndk1::char_traits<wchar_t>, std::__ndk1::allocator<wchar_t> >"),
523                                                          std_wstring_summary_sp);
524 
525     SyntheticChildren::Flags stl_synth_flags;
526     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
527 
528     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);
529     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_synth_flags, true);
530     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, "libc++ std::list synthetic children", ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), stl_synth_flags, true);
531     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::map synthetic children", ConstString("^std::__(ndk)?1::map<.+> >(( )?&)?$"), stl_synth_flags, true);
532     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);
533     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);
534     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_synth_flags, true);
535     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__(ndk)?1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true);
536     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__(ndk)?1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true);
537     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);
538     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, "libc++ std::initializer_list synthetic children", ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, true);
539     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, "libc++ std::atomic synthetic children", ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_synth_flags, true);
540 
541     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^(std::__(ndk)?1::)deque<.+>(( )?&)?$")),
542                                                                SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
543                                                                                                                  "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
544 
545     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "shared_ptr synthetic children", ConstString("^(std::__(ndk)?1::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
546     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "weak_ptr synthetic children", ConstString("^(std::__(ndk)?1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
547 
548     stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(false);
549     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);
550     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector summary provider", ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_summary_flags, true);
551     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::list summary provider", ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), stl_summary_flags, true);
552     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::map summary provider", ConstString("^std::__(ndk)?1::map<.+>(( )?&)?$"), stl_summary_flags, true);
553     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::deque summary provider", ConstString("^std::__(ndk)?1::deque<.+>(( )?&)?$"), stl_summary_flags, true);
554     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::set summary provider", ConstString("^std::__(ndk)?1::set<.+>(( )?&)?$"), stl_summary_flags, true);
555     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multiset summary provider", ConstString("^std::__(ndk)?1::multiset<.+>(( )?&)?$"), stl_summary_flags, true);
556     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multimap summary provider", ConstString("^std::__(ndk)?1::multimap<.+>(( )?&)?$"), stl_summary_flags, true);
557     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);
558     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider, "libc++ std::atomic summary provider", ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_summary_flags, true);
559 
560     stl_summary_flags.SetSkipPointers(true);
561 
562     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::shared_ptr summary provider", ConstString("^std::__(ndk)?1::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
563     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::weak_ptr summary provider", ConstString("^std::__(ndk)?1::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
564 
565     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^std::__(ndk)?1::__wrap_iter<.+>$"), stl_synth_flags, true);
566 
567     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);
568     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::__(ndk)?1::__map_iterator<.+>$"), stl_synth_flags, true);
569 
570     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxFunctionFrontEndCreator, "std::function synthetic value provider", ConstString("^std::__1::function<.+>$"), stl_synth_flags, true);
571 #endif
572 }
573 
574 static void
575 LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
576 {
577     if (!cpp_category_sp)
578         return;
579 
580     TypeSummaryImpl::Flags stl_summary_flags;
581     stl_summary_flags.SetCascades(true)
582     .SetSkipPointers(false)
583     .SetSkipReferences(false)
584     .SetDontShowChildren(true)
585     .SetDontShowValue(true)
586     .SetShowMembersOneLiner(false)
587     .SetHideItemNames(false);
588 
589     lldb::TypeSummaryImplSP std_string_summary_sp(new StringSummaryFormat(stl_summary_flags,
590                                                                           "${var._M_dataplus._M_p}"));
591 
592     lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags,
593                                                                                  LibStdcppStringSummaryProvider,
594                                                                                  "libstdc++ c++11 std::string summary provider"));
595     lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags,
596                                                                                  LibStdcppWStringSummaryProvider,
597                                                                                  "libstdc++ c++11 std::wstring summary provider"));
598 
599     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
600                                                       std_string_summary_sp);
601     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char>"),
602                                                       std_string_summary_sp);
603     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"),
604                                                       std_string_summary_sp);
605     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
606                                                       std_string_summary_sp);
607 
608     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::string"),
609                                                       cxx11_string_summary_sp);
610     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
611                                                       cxx11_string_summary_sp);
612 
613     // making sure we force-pick the summary for printing wstring (_M_p is a wchar_t*)
614     lldb::TypeSummaryImplSP std_wstring_summary_sp(new StringSummaryFormat(stl_summary_flags,
615                                                                            "${var._M_dataplus._M_p%S}"));
616 
617     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"),
618                                                       std_wstring_summary_sp);
619     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t>"),
620                                                       std_wstring_summary_sp);
621     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >"),
622                                                       std_wstring_summary_sp);
623     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
624                                                       std_wstring_summary_sp);
625 
626     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::wstring"),
627                                                       cxx11_wstring_summary_sp);
628     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
629                                                       cxx11_wstring_summary_sp);
630 
631 #ifndef LLDB_DISABLE_PYTHON
632 
633     SyntheticChildren::Flags stl_synth_flags;
634     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
635 
636     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
637                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
638                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
639     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
640                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
641                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider")));
642     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
643                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
644                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
645     stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(true);
646     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
647                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
648                                                                                                      "size=${svar%#}")));
649     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
650                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
651                                                                                                      "size=${svar%#}")));
652     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
653                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
654                                                                                                      "size=${svar%#}")));
655 
656     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
657 
658     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
659 
660     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
661                     "std::shared_ptr synthetic children", ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags,
662                     true);
663     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
664                     "std::weak_ptr synthetic children", ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags,
665                     true);
666 
667     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
668                   "libstdc++ std::shared_ptr summary provider", ConstString("^std::shared_ptr<.+>(( )?&)?$"),
669                   stl_summary_flags, true);
670     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
671                   "libstdc++ std::weak_ptr summary provider", ConstString("^std::weak_ptr<.+>(( )?&)?$"),
672                   stl_summary_flags, true);
673 #endif
674 }
675 
676 static void
677 LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
678 {
679     if (!cpp_category_sp)
680         return;
681 
682     TypeSummaryImpl::Flags string_flags;
683     string_flags.SetCascades(true)
684     .SetSkipPointers(true)
685     .SetSkipReferences(false)
686     .SetDontShowChildren(true)
687     .SetDontShowValue(false)
688     .SetShowMembersOneLiner(false)
689     .SetHideItemNames(false);
690 
691     TypeSummaryImpl::Flags string_array_flags;
692     string_array_flags.SetCascades(true)
693     .SetSkipPointers(true)
694     .SetSkipReferences(false)
695     .SetDontShowChildren(true)
696     .SetDontShowValue(true)
697     .SetShowMembersOneLiner(false)
698     .SetHideItemNames(false);
699 
700 #ifndef LLDB_DISABLE_PYTHON
701     // FIXME because of a bug in the FormattersContainer we need to add a summary for both X* and const X* (<rdar://problem/12717717>)
702     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "char16_t * summary provider", ConstString("char16_t *"), string_flags);
703     AddCXXSummary(cpp_category_sp,
704                   lldb_private::formatters::Char16StringSummaryProvider,
705                   "char16_t [] summary provider",
706                   ConstString("char16_t \\[[0-9]+\\]"),
707                   string_array_flags,
708                   true);
709 
710     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider, "char32_t * summary provider", ConstString("char32_t *"), string_flags);
711     AddCXXSummary(cpp_category_sp,
712                   lldb_private::formatters::Char32StringSummaryProvider,
713                   "char32_t [] summary provider",
714                   ConstString("char32_t \\[[0-9]+\\]"),
715                   string_array_flags,
716                   true);
717 
718     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
719     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true);
720 
721     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "unichar * summary provider", ConstString("unichar *"), string_flags);
722 
723     TypeSummaryImpl::Flags widechar_flags;
724     widechar_flags.SetDontShowValue(true)
725     .SetSkipPointers(true)
726     .SetSkipReferences(false)
727     .SetCascades(true)
728     .SetDontShowChildren(true)
729     .SetHideItemNames(true)
730     .SetShowMembersOneLiner(false);
731 
732     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, "char16_t summary provider", ConstString("char16_t"), widechar_flags);
733     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char32SummaryProvider, "char32_t summary provider", ConstString("char32_t"), widechar_flags);
734     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider, "wchar_t summary provider", ConstString("wchar_t"), widechar_flags);
735 
736     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, "unichar summary provider", ConstString("unichar"), widechar_flags);
737 #endif
738 }
739 
740 lldb::TypeCategoryImplSP
741 CPlusPlusLanguage::GetFormatters ()
742 {
743     static std::once_flag g_initialize;
744     static TypeCategoryImplSP g_category;
745 
746     std::call_once(g_initialize, [this] () -> void {
747         DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
748         if (g_category)
749         {
750             LoadLibCxxFormatters(g_category);
751             LoadLibStdcppFormatters(g_category);
752             LoadSystemFormatters(g_category);
753         }
754     });
755     return g_category;
756 }
757 
758 HardcodedFormatters::HardcodedSummaryFinder
759 CPlusPlusLanguage::GetHardcodedSummaries ()
760 {
761     static std::once_flag g_initialize;
762     static ConstString g_vectortypes("VectorTypes");
763     static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
764 
765     std::call_once(g_initialize, [] () -> void {
766         g_formatters.push_back(
767                                         [](lldb_private::ValueObject& valobj,
768                                            lldb::DynamicValueType,
769                                            FormatManager&) -> TypeSummaryImpl::SharedPointer {
770                                             static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags(), lldb_private::formatters::CXXFunctionPointerSummaryProvider, "Function pointer summary provider"));
771                                             if (valobj.GetCompilerType().IsFunctionPointerType())
772                                             {
773                                                 return formatter_sp;
774                                             }
775                                             return nullptr;
776                                         });
777         g_formatters.push_back(
778                                         [](lldb_private::ValueObject& valobj,
779                                            lldb::DynamicValueType,
780                                            FormatManager& fmt_mgr) -> TypeSummaryImpl::SharedPointer {
781                                             static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags()
782                                                                                                                                      .SetCascades(true)
783                                                                                                                                      .SetDontShowChildren(true)
784                                                                                                                                      .SetHideItemNames(true)
785                                                                                                                                      .SetShowMembersOneLiner(true)
786                                                                                                                                      .SetSkipPointers(true)
787                                                                                                                                      .SetSkipReferences(false),
788                                                                                                                                      lldb_private::formatters::VectorTypeSummaryProvider,
789                                                                                                                                      "vector_type pointer summary provider"));
790                                             if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr))
791                                             {
792                                                 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
793                                                     return formatter_sp;
794                                             }
795                                             return nullptr;
796                                         });
797         g_formatters.push_back(
798                                [](lldb_private::ValueObject& valobj,
799                                   lldb::DynamicValueType,
800                                   FormatManager& fmt_mgr) -> TypeSummaryImpl::SharedPointer {
801                                    static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags()
802                                                                                                                             .SetCascades(true)
803                                                                                                                             .SetDontShowChildren(true)
804                                                                                                                             .SetHideItemNames(true)
805                                                                                                                             .SetShowMembersOneLiner(true)
806                                                                                                                             .SetSkipPointers(true)
807                                                                                                                             .SetSkipReferences(false),
808                                                                                                                             lldb_private::formatters::BlockPointerSummaryProvider,
809                                                                                                                             "block pointer summary provider"));
810                                    if (valobj.GetCompilerType().IsBlockPointerType(nullptr))
811                                    {
812                                        return formatter_sp;
813                                    }
814                                    return nullptr;
815                                });
816     });
817 
818     return g_formatters;
819 }
820 
821 HardcodedFormatters::HardcodedSyntheticFinder
822 CPlusPlusLanguage::GetHardcodedSynthetics ()
823 {
824     static std::once_flag g_initialize;
825     static ConstString g_vectortypes("VectorTypes");
826     static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
827 
828     std::call_once(g_initialize, [] () -> void {
829         g_formatters.push_back(
830                                          [](lldb_private::ValueObject& valobj,
831                                             lldb::DynamicValueType,
832                                             FormatManager& fmt_mgr) -> SyntheticChildren::SharedPointer {
833                                              static CXXSyntheticChildren::SharedPointer formatter_sp(new CXXSyntheticChildren(SyntheticChildren::Flags().SetCascades(true).SetSkipPointers(true).SetSkipReferences(true).SetNonCacheable(true),
834                                                                                                                               "vector_type synthetic children",
835                                                                                                                               lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
836                                              if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr))
837                                              {
838                                                  if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
839                                                      return formatter_sp;
840                                              }
841                                              return nullptr;
842                                          });
843         g_formatters.push_back(
844                                          [](lldb_private::ValueObject& valobj,
845                                             lldb::DynamicValueType,
846                                             FormatManager& fmt_mgr) -> SyntheticChildren::SharedPointer {
847                                              static CXXSyntheticChildren::SharedPointer formatter_sp(new CXXSyntheticChildren(SyntheticChildren::Flags().SetCascades(true).SetSkipPointers(true).SetSkipReferences(true).SetNonCacheable(true),
848                                                                                                                               "block pointer synthetic children",
849                                                                                                                               lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
850                                              if (valobj.GetCompilerType().IsBlockPointerType(nullptr))
851                                              {
852                                                  return formatter_sp;
853                                              }
854                                              return nullptr;
855                                          });
856 
857     });
858 
859     return g_formatters;
860 }
861