xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (revision c530ba98a9ee2ab97fcae2fd28a366050aa35919)
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::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"),
508                                                          std_string_summary_sp);
509 
510     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::wstring"),
511                                                          std_wstring_summary_sp);
512     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"),
513                                                          std_wstring_summary_sp);
514 
515     SyntheticChildren::Flags stl_synth_flags;
516     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
517 
518     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", ConstString("^std::__1::vector<.+>(( )?&)?$"), stl_synth_flags, true);
519     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, "libc++ std::list synthetic children", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_synth_flags, true);
520     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::map synthetic children", ConstString("^std::__1::map<.+> >(( )?&)?$"), stl_synth_flags, true);
521     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, "libc++ std::vector<bool> synthetic children", ConstString("std::__1::vector<std::__1::allocator<bool> >"), stl_synth_flags);
522     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, "libc++ std::vector<bool> synthetic children", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_synth_flags);
523     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", ConstString("^std::__1::set<.+> >(( )?&)?$"), stl_synth_flags, true);
524     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true);
525     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true);
526     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, "libc++ std::unordered containers synthetic children", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_synth_flags, true);
527     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, "libc++ std::initializer_list synthetic children", ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, true);
528     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, "libc++ std::atomic synthetic children", ConstString("^std::__1::atomic<.+>$"), stl_synth_flags, true);
529 
530     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")),
531                                                                SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
532                                                                                                                  "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
533 
534     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "shared_ptr synthetic children", ConstString("^(std::__1::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
535     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "weak_ptr synthetic children", ConstString("^(std::__1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
536 
537     stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(false);
538     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, "libc++ std::vector<bool> synthetic children", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_synth_flags);
539 
540     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector summary provider", ConstString("^std::__1::vector<.+>(( )?&)?$"), stl_summary_flags, true);
541     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::list summary provider", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_summary_flags, true);
542     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::map summary provider", ConstString("^std::__1::map<.+>(( )?&)?$"), stl_summary_flags, true);
543     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::deque summary provider", ConstString("^std::__1::deque<.+>(( )?&)?$"), stl_summary_flags, true);
544     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector<bool> summary provider", ConstString("std::__1::vector<std::__1::allocator<bool> >"), stl_summary_flags);
545     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector<bool> summary provider", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_summary_flags);
546     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::set summary provider", ConstString("^std::__1::set<.+>(( )?&)?$"), stl_summary_flags, true);
547     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multiset summary provider", ConstString("^std::__1::multiset<.+>(( )?&)?$"), stl_summary_flags, true);
548     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multimap summary provider", ConstString("^std::__1::multimap<.+>(( )?&)?$"), stl_summary_flags, true);
549     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::unordered containers summary provider", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_summary_flags, true);
550     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider, "libc++ std::atomic summary provider", ConstString("^std::__1::atomic<.+>$"), stl_summary_flags, true);
551 
552     stl_summary_flags.SetSkipPointers(true);
553 
554     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::shared_ptr summary provider", ConstString("^std::__1::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
555     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::weak_ptr summary provider", ConstString("^std::__1::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
556 
557     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^std::__1::__wrap_iter<.+>$"), stl_synth_flags, true);
558 
559     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector<bool> summary provider", ConstString("std::__1::vector<bool, std::__1::allocator<bool> >"), stl_summary_flags);
560     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::__1::__map_iterator<.+>$"), stl_synth_flags, true);
561 #endif
562 }
563 
564 static void
565 LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
566 {
567     if (!cpp_category_sp)
568         return;
569 
570     TypeSummaryImpl::Flags stl_summary_flags;
571     stl_summary_flags.SetCascades(true)
572     .SetSkipPointers(false)
573     .SetSkipReferences(false)
574     .SetDontShowChildren(true)
575     .SetDontShowValue(true)
576     .SetShowMembersOneLiner(false)
577     .SetHideItemNames(false);
578 
579     lldb::TypeSummaryImplSP std_string_summary_sp(new StringSummaryFormat(stl_summary_flags,
580                                                                           "${var._M_dataplus._M_p}"));
581 
582     lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags,
583                                                                                  LibStdcppStringSummaryProvider,
584                                                                                  "libstdc++ c++11 std::string summary provider"));
585     lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags,
586                                                                                  LibStdcppWStringSummaryProvider,
587                                                                                  "libstdc++ c++11 std::wstring summary provider"));
588 
589     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
590                                                       std_string_summary_sp);
591     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char>"),
592                                                       std_string_summary_sp);
593     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"),
594                                                       std_string_summary_sp);
595     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
596                                                       std_string_summary_sp);
597 
598     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::string"),
599                                                       cxx11_string_summary_sp);
600     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
601                                                       cxx11_string_summary_sp);
602 
603     // making sure we force-pick the summary for printing wstring (_M_p is a wchar_t*)
604     lldb::TypeSummaryImplSP std_wstring_summary_sp(new StringSummaryFormat(stl_summary_flags,
605                                                                            "${var._M_dataplus._M_p%S}"));
606 
607     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"),
608                                                       std_wstring_summary_sp);
609     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t>"),
610                                                       std_wstring_summary_sp);
611     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >"),
612                                                       std_wstring_summary_sp);
613     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
614                                                       std_wstring_summary_sp);
615 
616     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::wstring"),
617                                                       cxx11_wstring_summary_sp);
618     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
619                                                       cxx11_wstring_summary_sp);
620 
621 #ifndef LLDB_DISABLE_PYTHON
622 
623     SyntheticChildren::Flags stl_synth_flags;
624     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
625 
626     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
627                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
628                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
629     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
630                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
631                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider")));
632     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
633                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
634                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
635     stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(true);
636     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
637                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
638                                                                                                      "size=${svar%#}")));
639     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
640                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
641                                                                                                      "size=${svar%#}")));
642     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
643                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
644                                                                                                      "size=${svar%#}")));
645 
646     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
647 
648     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
649 #endif
650 }
651 
652 static void
653 LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
654 {
655     if (!cpp_category_sp)
656         return;
657 
658     TypeSummaryImpl::Flags string_flags;
659     string_flags.SetCascades(true)
660     .SetSkipPointers(true)
661     .SetSkipReferences(false)
662     .SetDontShowChildren(true)
663     .SetDontShowValue(false)
664     .SetShowMembersOneLiner(false)
665     .SetHideItemNames(false);
666 
667     TypeSummaryImpl::Flags string_array_flags;
668     string_array_flags.SetCascades(true)
669     .SetSkipPointers(true)
670     .SetSkipReferences(false)
671     .SetDontShowChildren(true)
672     .SetDontShowValue(true)
673     .SetShowMembersOneLiner(false)
674     .SetHideItemNames(false);
675 
676 #ifndef LLDB_DISABLE_PYTHON
677     // FIXME because of a bug in the FormattersContainer we need to add a summary for both X* and const X* (<rdar://problem/12717717>)
678     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "char16_t * summary provider", ConstString("char16_t *"), string_flags);
679     AddCXXSummary(cpp_category_sp,
680                   lldb_private::formatters::Char16StringSummaryProvider,
681                   "char16_t [] summary provider",
682                   ConstString("char16_t \\[[0-9]+\\]"),
683                   string_array_flags,
684                   true);
685 
686     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider, "char32_t * summary provider", ConstString("char32_t *"), string_flags);
687     AddCXXSummary(cpp_category_sp,
688                   lldb_private::formatters::Char32StringSummaryProvider,
689                   "char32_t [] summary provider",
690                   ConstString("char32_t \\[[0-9]+\\]"),
691                   string_array_flags,
692                   true);
693 
694     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
695     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true);
696 
697     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "unichar * summary provider", ConstString("unichar *"), string_flags);
698 
699     TypeSummaryImpl::Flags widechar_flags;
700     widechar_flags.SetDontShowValue(true)
701     .SetSkipPointers(true)
702     .SetSkipReferences(false)
703     .SetCascades(true)
704     .SetDontShowChildren(true)
705     .SetHideItemNames(true)
706     .SetShowMembersOneLiner(false);
707 
708     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, "char16_t summary provider", ConstString("char16_t"), widechar_flags);
709     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char32SummaryProvider, "char32_t summary provider", ConstString("char32_t"), widechar_flags);
710     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider, "wchar_t summary provider", ConstString("wchar_t"), widechar_flags);
711 
712     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, "unichar summary provider", ConstString("unichar"), widechar_flags);
713 #endif
714 }
715 
716 lldb::TypeCategoryImplSP
717 CPlusPlusLanguage::GetFormatters ()
718 {
719     static std::once_flag g_initialize;
720     static TypeCategoryImplSP g_category;
721 
722     std::call_once(g_initialize, [this] () -> void {
723         DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
724         if (g_category)
725         {
726             LoadLibCxxFormatters(g_category);
727             LoadLibStdcppFormatters(g_category);
728             LoadSystemFormatters(g_category);
729         }
730     });
731     return g_category;
732 }
733 
734 HardcodedFormatters::HardcodedSummaryFinder
735 CPlusPlusLanguage::GetHardcodedSummaries ()
736 {
737     static std::once_flag g_initialize;
738     static ConstString g_vectortypes("VectorTypes");
739     static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
740 
741     std::call_once(g_initialize, [] () -> void {
742         g_formatters.push_back(
743                                         [](lldb_private::ValueObject& valobj,
744                                            lldb::DynamicValueType,
745                                            FormatManager&) -> TypeSummaryImpl::SharedPointer {
746                                             static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags(), lldb_private::formatters::CXXFunctionPointerSummaryProvider, "Function pointer summary provider"));
747                                             if (valobj.GetCompilerType().IsFunctionPointerType())
748                                             {
749                                                 return formatter_sp;
750                                             }
751                                             return nullptr;
752                                         });
753         g_formatters.push_back(
754                                         [](lldb_private::ValueObject& valobj,
755                                            lldb::DynamicValueType,
756                                            FormatManager& fmt_mgr) -> TypeSummaryImpl::SharedPointer {
757                                             static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags()
758                                                                                                                                      .SetCascades(true)
759                                                                                                                                      .SetDontShowChildren(true)
760                                                                                                                                      .SetHideItemNames(true)
761                                                                                                                                      .SetShowMembersOneLiner(true)
762                                                                                                                                      .SetSkipPointers(true)
763                                                                                                                                      .SetSkipReferences(false),
764                                                                                                                                      lldb_private::formatters::VectorTypeSummaryProvider,
765                                                                                                                                      "vector_type pointer summary provider"));
766                                             if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr))
767                                             {
768                                                 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
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::BlockPointerSummaryProvider,
785                                                                                                                             "block pointer summary provider"));
786                                    if (valobj.GetCompilerType().IsBlockPointerType(nullptr))
787                                    {
788                                        return formatter_sp;
789                                    }
790                                    return nullptr;
791                                });
792     });
793 
794     return g_formatters;
795 }
796 
797 HardcodedFormatters::HardcodedSyntheticFinder
798 CPlusPlusLanguage::GetHardcodedSynthetics ()
799 {
800     static std::once_flag g_initialize;
801     static ConstString g_vectortypes("VectorTypes");
802     static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
803 
804     std::call_once(g_initialize, [] () -> void {
805         g_formatters.push_back(
806                                          [](lldb_private::ValueObject& valobj,
807                                             lldb::DynamicValueType,
808                                             FormatManager& fmt_mgr) -> SyntheticChildren::SharedPointer {
809                                              static CXXSyntheticChildren::SharedPointer formatter_sp(new CXXSyntheticChildren(SyntheticChildren::Flags().SetCascades(true).SetSkipPointers(true).SetSkipReferences(true).SetNonCacheable(true),
810                                                                                                                               "vector_type synthetic children",
811                                                                                                                               lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
812                                              if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr))
813                                              {
814                                                  if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
815                                                      return formatter_sp;
816                                              }
817                                              return nullptr;
818                                          });
819         g_formatters.push_back(
820                                          [](lldb_private::ValueObject& valobj,
821                                             lldb::DynamicValueType,
822                                             FormatManager& fmt_mgr) -> SyntheticChildren::SharedPointer {
823                                              static CXXSyntheticChildren::SharedPointer formatter_sp(new CXXSyntheticChildren(SyntheticChildren::Flags().SetCascades(true).SetSkipPointers(true).SetSkipReferences(true).SetNonCacheable(true),
824                                                                                                                               "block pointer synthetic children",
825                                                                                                                               lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
826                                              if (valobj.GetCompilerType().IsBlockPointerType(nullptr))
827                                              {
828                                                  return formatter_sp;
829                                              }
830                                              return nullptr;
831                                          });
832 
833     });
834 
835     return g_formatters;
836 }
837