xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (revision c6bbb8b69a111a47d818c1c1b1bc0f379484d84c)
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 #include <string.h>
13 
14 #include "llvm/ADT/StringRef.h"
15 
16 #include "lldb/Core/ConstString.h"
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Core/RegularExpression.h"
19 #include "lldb/Core/UniqueCStringMap.h"
20 #include "lldb/DataFormatters/DataVisualization.h"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 
23 #include "CxxStringTypes.h"
24 #include "LibCxx.h"
25 #include "LibStdcpp.h"
26 
27 #include <functional>
28 #include <mutex>
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 using namespace lldb_private::formatters;
33 
34 void
35 CPlusPlusLanguage::Initialize()
36 {
37     PluginManager::RegisterPlugin (GetPluginNameStatic(),
38                                    "C++ Language",
39                                    CreateInstance);
40 }
41 
42 void
43 CPlusPlusLanguage::Terminate()
44 {
45     PluginManager::UnregisterPlugin (CreateInstance);
46 }
47 
48 lldb_private::ConstString
49 CPlusPlusLanguage::GetPluginNameStatic()
50 {
51     static ConstString g_name("cplusplus");
52     return g_name;
53 }
54 
55 
56 //------------------------------------------------------------------
57 // PluginInterface protocol
58 //------------------------------------------------------------------
59 lldb_private::ConstString
60 CPlusPlusLanguage::GetPluginName()
61 {
62     return GetPluginNameStatic();
63 }
64 
65 uint32_t
66 CPlusPlusLanguage::GetPluginVersion()
67 {
68     return 1;
69 }
70 
71 //------------------------------------------------------------------
72 // Static Functions
73 //------------------------------------------------------------------
74 Language *
75 CPlusPlusLanguage::CreateInstance (lldb::LanguageType language)
76 {
77     if (Language::LanguageIsCPlusPlus(language))
78         return new CPlusPlusLanguage();
79     return nullptr;
80 }
81 
82 void
83 CPlusPlusLanguage::MethodName::Clear()
84 {
85     m_full.Clear();
86     m_basename = llvm::StringRef();
87     m_context = llvm::StringRef();
88     m_arguments = llvm::StringRef();
89     m_qualifiers = llvm::StringRef();
90     m_type = eTypeInvalid;
91     m_parsed = false;
92     m_parse_error = false;
93 }
94 
95 bool
96 ReverseFindMatchingChars (const llvm::StringRef &s,
97                           const llvm::StringRef &left_right_chars,
98                           size_t &left_pos,
99                           size_t &right_pos,
100                           size_t pos = llvm::StringRef::npos)
101 {
102     assert (left_right_chars.size() == 2);
103     left_pos = llvm::StringRef::npos;
104     const char left_char = left_right_chars[0];
105     const char right_char = left_right_chars[1];
106     pos = s.find_last_of(left_right_chars, pos);
107     if (pos == llvm::StringRef::npos || s[pos] == left_char)
108         return false;
109     right_pos = pos;
110     uint32_t depth = 1;
111     while (pos > 0 && depth > 0)
112     {
113         pos = s.find_last_of(left_right_chars, pos);
114         if (pos == llvm::StringRef::npos)
115             return false;
116         if (s[pos] == left_char)
117         {
118             if (--depth == 0)
119             {
120                 left_pos = pos;
121                 return left_pos < right_pos;
122             }
123         }
124         else if (s[pos] == right_char)
125         {
126             ++depth;
127         }
128     }
129     return false;
130 }
131 
132 
133 void
134 CPlusPlusLanguage::MethodName::Parse()
135 {
136     if (!m_parsed && m_full)
137     {
138 //        ConstString mangled;
139 //        m_full.GetMangledCounterpart(mangled);
140 //        printf ("\n   parsing = '%s'\n", m_full.GetCString());
141 //        if (mangled)
142 //            printf ("   mangled = '%s'\n", mangled.GetCString());
143         m_parse_error = false;
144         m_parsed = true;
145         llvm::StringRef full (m_full.GetCString());
146 
147         size_t arg_start, arg_end;
148         llvm::StringRef parens("()", 2);
149         if (ReverseFindMatchingChars (full, parens, arg_start, arg_end))
150         {
151             m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
152             if (arg_end + 1 < full.size())
153                 m_qualifiers = full.substr(arg_end + 1);
154             if (arg_start > 0)
155             {
156                 size_t basename_end = arg_start;
157                 size_t context_start = 0;
158                 size_t context_end = llvm::StringRef::npos;
159                 if (basename_end > 0 && full[basename_end-1] == '>')
160                 {
161                     // TODO: handle template junk...
162                     // Templated function
163                     size_t template_start, template_end;
164                     llvm::StringRef lt_gt("<>", 2);
165                     if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end))
166                     {
167                         // Check for templated functions that include return type like: 'void foo<Int>()'
168                         context_start = full.rfind(' ', template_start);
169                         if (context_start == llvm::StringRef::npos)
170                             context_start = 0;
171 
172                         context_end = full.rfind(':', template_start);
173                         if (context_end == llvm::StringRef::npos || context_end < context_start)
174                             context_end = context_start;
175                     }
176                     else
177                     {
178                         context_end = full.rfind(':', basename_end);
179                     }
180                 }
181                 else if (context_end == llvm::StringRef::npos)
182                 {
183                     context_end = full.rfind(':', basename_end);
184                 }
185 
186                 if (context_end == llvm::StringRef::npos)
187                     m_basename = full.substr(0, basename_end);
188                 else
189                 {
190                     if (context_start < context_end)
191                         m_context = full.substr(context_start, context_end - 1);
192                     const size_t basename_begin = context_end + 1;
193                     m_basename = full.substr(basename_begin, basename_end - basename_begin);
194                 }
195                 m_type = eTypeUnknownMethod;
196             }
197             else
198             {
199                 m_parse_error = true;
200                 return;
201             }
202 
203 //            if (!m_context.empty())
204 //                printf ("   context = '%s'\n", m_context.str().c_str());
205 //            if (m_basename)
206 //                printf ("  basename = '%s'\n", m_basename.GetCString());
207 //            if (!m_arguments.empty())
208 //                printf (" arguments = '%s'\n", m_arguments.str().c_str());
209 //            if (!m_qualifiers.empty())
210 //                printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str());
211 
212             // Make sure we have a valid C++ basename with optional template args
213             static RegularExpression g_identifier_regex("^~?([A-Za-z_][A-Za-z_0-9]*)(<.*>)?$");
214             std::string basename_str(m_basename.str());
215             bool basename_is_valid = g_identifier_regex.Execute (basename_str.c_str(), NULL);
216             if (!basename_is_valid)
217             {
218                 // Check for C++ operators
219                 if (m_basename.startswith("operator"))
220                 {
221                     static RegularExpression g_operator_regex("^(operator)( ?)([A-Za-z_][A-Za-z_0-9]*|\\(\\)|\\[\\]|[\\^<>=!\\/*+-]+)(<.*>)?(\\[\\])?$");
222                     basename_is_valid = g_operator_regex.Execute(basename_str.c_str(), NULL);
223                 }
224             }
225             if (!basename_is_valid)
226             {
227                 // The C++ basename doesn't match our regular expressions so this can't
228                 // be a valid C++ method, clear everything out and indicate an error
229                 m_context = llvm::StringRef();
230                 m_basename = llvm::StringRef();
231                 m_arguments = llvm::StringRef();
232                 m_qualifiers = llvm::StringRef();
233                 m_parse_error = true;
234             }
235         }
236         else
237         {
238             m_parse_error = true;
239 //            printf ("error: didn't find matching parens for arguments\n");
240         }
241     }
242 }
243 
244 llvm::StringRef
245 CPlusPlusLanguage::MethodName::GetBasename ()
246 {
247     if (!m_parsed)
248         Parse();
249     return m_basename;
250 }
251 
252 llvm::StringRef
253 CPlusPlusLanguage::MethodName::GetContext ()
254 {
255     if (!m_parsed)
256         Parse();
257     return m_context;
258 }
259 
260 llvm::StringRef
261 CPlusPlusLanguage::MethodName::GetArguments ()
262 {
263     if (!m_parsed)
264         Parse();
265     return m_arguments;
266 }
267 
268 llvm::StringRef
269 CPlusPlusLanguage::MethodName::GetQualifiers ()
270 {
271     if (!m_parsed)
272         Parse();
273     return m_qualifiers;
274 }
275 
276 bool
277 CPlusPlusLanguage::IsCPPMangledName (const char *name)
278 {
279     // FIXME, we should really run through all the known C++ Language plugins and ask each one if
280     // this is a C++ mangled name, but we can put that off till there is actually more than one
281     // we care about.
282 
283     if (name && name[0] == '_' && name[1] == 'Z')
284         return true;
285     else
286         return false;
287 }
288 
289 bool
290 CPlusPlusLanguage::ExtractContextAndIdentifier (const char *name, llvm::StringRef &context, llvm::StringRef &identifier)
291 {
292     static RegularExpression g_basename_regex("^(([A-Za-z_][A-Za-z_0-9]*::)*)([A-Za-z_][A-Za-z_0-9]*)$");
293     RegularExpression::Match match(4);
294     if (g_basename_regex.Execute (name, &match))
295     {
296         match.GetMatchAtIndex(name, 1, context);
297         match.GetMatchAtIndex(name, 3, identifier);
298         return true;
299     }
300     return false;
301 }
302 
303 class CPPRuntimeEquivalents
304 {
305 public:
306     CPPRuntimeEquivalents ()
307     {
308 
309         m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("basic_string<char>"));
310 
311         // these two (with a prefixed std::) occur when c++stdlib string class occurs as a template argument in some STL container
312         m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("std::basic_string<char>"));
313 
314         m_impl.Sort();
315     }
316 
317     void
318     Add (ConstString& type_name,
319          ConstString& type_equivalent)
320     {
321         m_impl.Insert(type_name.AsCString(), type_equivalent);
322     }
323 
324     uint32_t
325     FindExactMatches (ConstString& type_name,
326                       std::vector<ConstString>& equivalents)
327     {
328 
329         uint32_t count = 0;
330 
331         for (ImplData match = m_impl.FindFirstValueForName(type_name.AsCString());
332              match != NULL;
333              match = m_impl.FindNextValueForName(match))
334         {
335             equivalents.push_back(match->value);
336             count++;
337         }
338 
339         return count;
340     }
341 
342     // partial matches can occur when a name with equivalents is a template argument.
343     // e.g. we may have "class Foo" be a match for "struct Bar". if we have a typename
344     // such as "class Templatized<class Foo, Anything>" we want this to be replaced with
345     // "class Templatized<struct Bar, Anything>". Since partial matching is time consuming
346     // once we get a partial match, we add it to the exact matches list for faster retrieval
347     uint32_t
348     FindPartialMatches (ConstString& type_name,
349                         std::vector<ConstString>& equivalents)
350     {
351 
352         uint32_t count = 0;
353 
354         const char* type_name_cstr = type_name.AsCString();
355 
356         size_t items_count = m_impl.GetSize();
357 
358         for (size_t item = 0; item < items_count; item++)
359         {
360             const char* key_cstr = m_impl.GetCStringAtIndex(item);
361             if ( strstr(type_name_cstr,key_cstr) )
362             {
363                 count += AppendReplacements(type_name_cstr,
364                                             key_cstr,
365                                             equivalents);
366             }
367         }
368 
369         return count;
370 
371     }
372 
373 private:
374 
375     std::string& replace (std::string& target,
376                           std::string& pattern,
377                           std::string& with)
378     {
379         size_t pos;
380         size_t pattern_len = pattern.size();
381 
382         while ( (pos = target.find(pattern)) != std::string::npos )
383             target.replace(pos, pattern_len, with);
384 
385         return target;
386     }
387 
388     uint32_t
389     AppendReplacements (const char* original,
390                         const char *matching_key,
391                         std::vector<ConstString>& equivalents)
392     {
393 
394         std::string matching_key_str(matching_key);
395         ConstString original_const(original);
396 
397         uint32_t count = 0;
398 
399         for (ImplData match = m_impl.FindFirstValueForName(matching_key);
400              match != NULL;
401              match = m_impl.FindNextValueForName(match))
402         {
403             std::string target(original);
404             std::string equiv_class(match->value.AsCString());
405 
406             replace (target, matching_key_str, equiv_class);
407 
408             ConstString target_const(target.c_str());
409 
410 // you will most probably want to leave this off since it might make this map grow indefinitely
411 #ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW
412             Add(original_const, target_const);
413 #endif
414             equivalents.push_back(target_const);
415 
416             count++;
417         }
418 
419         return count;
420     }
421 
422     typedef UniqueCStringMap<ConstString> Impl;
423     typedef const Impl::Entry* ImplData;
424     Impl m_impl;
425 };
426 
427 static CPPRuntimeEquivalents&
428 GetEquivalentsMap ()
429 {
430     static CPPRuntimeEquivalents g_equivalents_map;
431     return g_equivalents_map;
432 }
433 
434 
435 uint32_t
436 CPlusPlusLanguage::FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents)
437 {
438     uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents);
439 
440     bool might_have_partials=
441         ( count == 0 )  // if we have a full name match just use it
442         && (strchr(type_name.AsCString(), '<') != NULL  // we should only have partial matches when templates are involved, check that we have
443             && strchr(type_name.AsCString(), '>') != NULL); // angle brackets in the type_name before trying to scan for partial matches
444 
445     if ( might_have_partials )
446         count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents);
447 
448     return count;
449 }
450 
451 static void
452 LoadLibCxxFormatters (lldb::TypeCategoryImplSP cpp_category_sp)
453 {
454     if (!cpp_category_sp)
455         return;
456 
457     TypeSummaryImpl::Flags stl_summary_flags;
458     stl_summary_flags.SetCascades(true)
459     .SetSkipPointers(false)
460     .SetSkipReferences(false)
461     .SetDontShowChildren(true)
462     .SetDontShowValue(true)
463     .SetShowMembersOneLiner(false)
464     .SetHideItemNames(false);
465 
466 #ifndef LLDB_DISABLE_PYTHON
467     lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider, "std::string summary provider"));
468     lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, "std::wstring summary provider"));
469 
470     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::string"),
471                                                          std_string_summary_sp);
472     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"),
473                                                          std_string_summary_sp);
474 
475     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::wstring"),
476                                                          std_wstring_summary_sp);
477     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"),
478                                                          std_wstring_summary_sp);
479 
480     SyntheticChildren::Flags stl_synth_flags;
481     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
482 
483     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", ConstString("^std::__1::vector<.+>(( )?&)?$"), stl_synth_flags, true);
484     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, "libc++ std::list synthetic children", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_synth_flags, true);
485     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::map synthetic children", ConstString("^std::__1::map<.+> >(( )?&)?$"), stl_synth_flags, true);
486     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);
487     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);
488     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", ConstString("^std::__1::set<.+> >(( )?&)?$"), stl_synth_flags, true);
489     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true);
490     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true);
491     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);
492     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, "libc++ std::initializer_list synthetic children", ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, true);
493 
494     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")),
495                                                                SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
496                                                                                                                  "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
497 
498     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "shared_ptr synthetic children", ConstString("^(std::__1::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
499     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "weak_ptr synthetic children", ConstString("^(std::__1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
500 
501     stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(false);
502     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);
503 
504     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector summary provider", ConstString("^std::__1::vector<.+>(( )?&)?$"), stl_summary_flags, true);
505     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::list summary provider", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_summary_flags, true);
506     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::map summary provider", ConstString("^std::__1::map<.+>(( )?&)?$"), stl_summary_flags, true);
507     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::deque summary provider", ConstString("^std::__1::deque<.+>(( )?&)?$"), stl_summary_flags, true);
508     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);
509     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);
510     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::set summary provider", ConstString("^std::__1::set<.+>(( )?&)?$"), stl_summary_flags, true);
511     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multiset summary provider", ConstString("^std::__1::multiset<.+>(( )?&)?$"), stl_summary_flags, true);
512     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multimap summary provider", ConstString("^std::__1::multimap<.+>(( )?&)?$"), stl_summary_flags, true);
513     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);
514 
515     stl_summary_flags.SetSkipPointers(true);
516 
517     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::shared_ptr summary provider", ConstString("^std::__1::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
518     AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::weak_ptr summary provider", ConstString("^std::__1::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
519 
520     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^std::__1::__wrap_iter<.+>$"), stl_synth_flags, true);
521 
522     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);
523     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::__1::__map_iterator<.+>$"), stl_synth_flags, true);
524 
525     AddFilter(cpp_category_sp, {"__a_"}, "libc++ std::atomic filter", ConstString("^std::__1::atomic<.*>$"), stl_synth_flags, true);
526 #endif
527 }
528 
529 static void
530 LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
531 {
532     if (!cpp_category_sp)
533         return;
534 
535     TypeSummaryImpl::Flags stl_summary_flags;
536     stl_summary_flags.SetCascades(true)
537     .SetSkipPointers(false)
538     .SetSkipReferences(false)
539     .SetDontShowChildren(true)
540     .SetDontShowValue(true)
541     .SetShowMembersOneLiner(false)
542     .SetHideItemNames(false);
543 
544     lldb::TypeSummaryImplSP std_string_summary_sp(new StringSummaryFormat(stl_summary_flags,
545                                                                           "${var._M_dataplus._M_p}"));
546 
547     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
548                                                       std_string_summary_sp);
549     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char>"),
550                                                       std_string_summary_sp);
551     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"),
552                                                       std_string_summary_sp);
553     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
554                                                       std_string_summary_sp);
555 
556     // making sure we force-pick the summary for printing wstring (_M_p is a wchar_t*)
557     lldb::TypeSummaryImplSP std_wstring_summary_sp(new StringSummaryFormat(stl_summary_flags,
558                                                                            "${var._M_dataplus._M_p%S}"));
559 
560     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"),
561                                                       std_wstring_summary_sp);
562     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t>"),
563                                                       std_wstring_summary_sp);
564     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >"),
565                                                       std_wstring_summary_sp);
566     cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
567                                                       std_wstring_summary_sp);
568 
569 
570 #ifndef LLDB_DISABLE_PYTHON
571 
572     SyntheticChildren::Flags stl_synth_flags;
573     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
574 
575     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
576                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
577                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
578     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
579                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
580                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider")));
581     cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")),
582                                                             SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
583                                                                                                               "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
584 
585     stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(true);
586     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
587                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
588                                                                                                      "size=${svar%#}")));
589     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
590                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
591                                                                                                      "size=${svar%#}")));
592     cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")),
593                                                            TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
594                                                                                                      "size=${svar%#}")));
595 
596     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
597 
598     AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
599 #endif
600 }
601 
602 static void
603 LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
604 {
605     if (!cpp_category_sp)
606         return;
607 
608     TypeSummaryImpl::Flags string_flags;
609     string_flags.SetCascades(true)
610     .SetSkipPointers(true)
611     .SetSkipReferences(false)
612     .SetDontShowChildren(true)
613     .SetDontShowValue(false)
614     .SetShowMembersOneLiner(false)
615     .SetHideItemNames(false);
616 
617     TypeSummaryImpl::Flags string_array_flags;
618     string_array_flags.SetCascades(true)
619     .SetSkipPointers(true)
620     .SetSkipReferences(false)
621     .SetDontShowChildren(true)
622     .SetDontShowValue(true)
623     .SetShowMembersOneLiner(false)
624     .SetHideItemNames(false);
625 
626 #ifndef LLDB_DISABLE_PYTHON
627     // FIXME because of a bug in the FormattersContainer we need to add a summary for both X* and const X* (<rdar://problem/12717717>)
628     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "char16_t * summary provider", ConstString("char16_t *"), string_flags);
629 
630     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider, "char32_t * summary provider", ConstString("char32_t *"), string_flags);
631 
632     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
633     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true);
634 
635     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "unichar * summary provider", ConstString("unichar *"), string_flags);
636 
637     TypeSummaryImpl::Flags widechar_flags;
638     widechar_flags.SetDontShowValue(true)
639     .SetSkipPointers(true)
640     .SetSkipReferences(false)
641     .SetCascades(true)
642     .SetDontShowChildren(true)
643     .SetHideItemNames(true)
644     .SetShowMembersOneLiner(false);
645 
646     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, "char16_t summary provider", ConstString("char16_t"), widechar_flags);
647     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char32SummaryProvider, "char32_t summary provider", ConstString("char32_t"), widechar_flags);
648     AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider, "wchar_t summary provider", ConstString("wchar_t"), widechar_flags);
649 
650     AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, "unichar summary provider", ConstString("unichar"), widechar_flags);
651 #endif
652 }
653 
654 lldb::TypeCategoryImplSP
655 CPlusPlusLanguage::GetFormatters ()
656 {
657     static std::once_flag g_initialize;
658     static TypeCategoryImplSP g_category;
659 
660     std::call_once(g_initialize, [this] () -> void {
661         DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
662         if (g_category)
663         {
664             LoadLibCxxFormatters(g_category);
665             LoadLibStdcppFormatters(g_category);
666             LoadSystemFormatters(g_category);
667         }
668     });
669     return g_category;
670 }
671 
672