xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1 //===-- CPlusPlusLanguage.cpp ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CPlusPlusLanguage.h"
10 
11 #include <cctype>
12 #include <cstring>
13 
14 #include <functional>
15 #include <memory>
16 #include <mutex>
17 #include <set>
18 
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Demangle/ItaniumDemangle.h"
21 
22 #include "lldb/Core/Mangled.h"
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/PluginManager.h"
25 #include "lldb/Core/UniqueCStringMap.h"
26 #include "lldb/DataFormatters/CXXFunctionPointer.h"
27 #include "lldb/DataFormatters/DataVisualization.h"
28 #include "lldb/DataFormatters/FormattersHelpers.h"
29 #include "lldb/DataFormatters/VectorType.h"
30 #include "lldb/Interpreter/OptionValueProperties.h"
31 #include "lldb/Symbol/SymbolFile.h"
32 #include "lldb/Symbol/VariableList.h"
33 #include "lldb/Utility/ConstString.h"
34 #include "lldb/Utility/LLDBLog.h"
35 #include "lldb/Utility/Log.h"
36 #include "lldb/Utility/RegularExpression.h"
37 #include "lldb/ValueObject/ValueObjectVariable.h"
38 
39 #include "BlockPointer.h"
40 #include "CPlusPlusNameParser.h"
41 #include "Coroutines.h"
42 #include "CxxStringTypes.h"
43 #include "Generic.h"
44 #include "LibCxx.h"
45 #include "LibCxxAtomic.h"
46 #include "LibCxxVariant.h"
47 #include "LibStdcpp.h"
48 #include "MSVCUndecoratedNameParser.h"
49 #include "MsvcStl.h"
50 #include "lldb/lldb-enumerations.h"
51 
52 using namespace lldb;
53 using namespace lldb_private;
54 using namespace lldb_private::formatters;
55 
LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)56 LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)
57 
58 void CPlusPlusLanguage::Initialize() {
59   PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
60                                 CreateInstance, &DebuggerInitialize);
61 }
62 
Terminate()63 void CPlusPlusLanguage::Terminate() {
64   PluginManager::UnregisterPlugin(CreateInstance);
65 }
66 
67 std::unique_ptr<Language::MethodName>
GetMethodName(ConstString full_name) const68 CPlusPlusLanguage::GetMethodName(ConstString full_name) const {
69   std::unique_ptr<CxxMethodName> cpp_method =
70       std::make_unique<CxxMethodName>(full_name);
71   cpp_method->IsValid();
72   return cpp_method;
73 }
74 
75 std::pair<FunctionNameType, std::optional<ConstString>>
GetFunctionNameInfo(ConstString name) const76 CPlusPlusLanguage::GetFunctionNameInfo(ConstString name) const {
77   if (Mangled::IsMangledName(name.GetCString()))
78     return {eFunctionNameTypeFull, std::nullopt};
79 
80   FunctionNameType func_name_type = eFunctionNameTypeNone;
81   CxxMethodName method(name);
82   llvm::StringRef basename = method.GetBasename();
83   if (basename.empty()) {
84     llvm::StringRef context;
85     func_name_type |=
86         (ExtractContextAndIdentifier(name.GetCString(), context, basename)
87              ? (eFunctionNameTypeMethod | eFunctionNameTypeBase)
88              : eFunctionNameTypeFull);
89   } else {
90     func_name_type |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
91   }
92 
93   if (!method.GetQualifiers().empty()) {
94     // There is a 'const' or other qualifier following the end of the function
95     // parens, this can't be a eFunctionNameTypeBase.
96     func_name_type &= ~(eFunctionNameTypeBase);
97   }
98 
99   if (basename.empty())
100     return {func_name_type, std::nullopt};
101   else
102     return {func_name_type, ConstString(basename)};
103 }
104 
SymbolNameFitsToLanguage(Mangled mangled) const105 bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
106   const char *mangled_name = mangled.GetMangledName().GetCString();
107   return mangled_name && Mangled::IsMangledName(mangled_name);
108 }
109 
GetDemangledFunctionNameWithoutArguments(Mangled mangled) const110 ConstString CPlusPlusLanguage::GetDemangledFunctionNameWithoutArguments(
111     Mangled mangled) const {
112   const char *mangled_name_cstr = mangled.GetMangledName().GetCString();
113   ConstString demangled_name = mangled.GetDemangledName();
114   if (demangled_name && mangled_name_cstr && mangled_name_cstr[0]) {
115     if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
116         (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure,
117                                         // typeinfo structure, and typeinfo
118                                         // mangled_name
119          mangled_name_cstr[2] != 'G' && // avoid guard variables
120          mangled_name_cstr[2] != 'Z'))  // named local entities (if we
121                                         // eventually handle eSymbolTypeData,
122                                         // we will want this back)
123     {
124       CxxMethodName cxx_method(demangled_name);
125       if (!cxx_method.GetBasename().empty()) {
126         std::string shortname;
127         if (!cxx_method.GetContext().empty())
128           shortname = cxx_method.GetContext().str() + "::";
129         shortname += cxx_method.GetBasename().str();
130         return ConstString(shortname);
131       }
132     }
133   }
134   if (demangled_name)
135     return demangled_name;
136   return mangled.GetMangledName();
137 }
138 
139 // Static Functions
140 
CreateInstance(lldb::LanguageType language)141 Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) {
142   // Use plugin for C++ but not for Objective-C++ (which has its own plugin).
143   if (Language::LanguageIsCPlusPlus(language) &&
144       language != eLanguageTypeObjC_plus_plus)
145     return new CPlusPlusLanguage();
146   return nullptr;
147 }
148 
ReverseFindMatchingChars(const llvm::StringRef & s,const llvm::StringRef & left_right_chars,size_t & left_pos,size_t & right_pos,size_t pos=llvm::StringRef::npos)149 static bool ReverseFindMatchingChars(const llvm::StringRef &s,
150                                      const llvm::StringRef &left_right_chars,
151                                      size_t &left_pos, size_t &right_pos,
152                                      size_t pos = llvm::StringRef::npos) {
153   assert(left_right_chars.size() == 2);
154   left_pos = llvm::StringRef::npos;
155   const char left_char = left_right_chars[0];
156   const char right_char = left_right_chars[1];
157   pos = s.find_last_of(left_right_chars, pos);
158   if (pos == llvm::StringRef::npos || s[pos] == left_char)
159     return false;
160   right_pos = pos;
161   uint32_t depth = 1;
162   while (pos > 0 && depth > 0) {
163     pos = s.find_last_of(left_right_chars, pos);
164     if (pos == llvm::StringRef::npos)
165       return false;
166     if (s[pos] == left_char) {
167       if (--depth == 0) {
168         left_pos = pos;
169         return left_pos < right_pos;
170       }
171     } else if (s[pos] == right_char) {
172       ++depth;
173     }
174   }
175   return false;
176 }
177 
IsTrivialBasename(const llvm::StringRef & basename)178 static bool IsTrivialBasename(const llvm::StringRef &basename) {
179   // Check that the basename matches with the following regular expression
180   // "^~?([A-Za-z_][A-Za-z_0-9]*)$" We are using a hand written implementation
181   // because it is significantly more efficient then using the general purpose
182   // regular expression library.
183   size_t idx = 0;
184   if (basename.starts_with('~'))
185     idx = 1;
186 
187   if (basename.size() <= idx)
188     return false; // Empty string or "~"
189 
190   if (!std::isalpha(basename[idx]) && basename[idx] != '_')
191     return false; // First character (after removing the possible '~'') isn't in
192                   // [A-Za-z_]
193 
194   // Read all characters matching [A-Za-z_0-9]
195   ++idx;
196   while (idx < basename.size()) {
197     if (!std::isalnum(basename[idx]) && basename[idx] != '_')
198       break;
199     ++idx;
200   }
201 
202   // We processed all characters. It is a vaild basename.
203   return idx == basename.size();
204 }
205 
206 /// Writes out the function name in 'full_name' to 'out_stream'
207 /// but replaces each argument type with the variable name
208 /// and the corresponding pretty-printed value
PrettyPrintFunctionNameWithArgs(Stream & out_stream,char const * full_name,ExecutionContextScope * exe_scope,VariableList const & args)209 static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
210                                             char const *full_name,
211                                             ExecutionContextScope *exe_scope,
212                                             VariableList const &args) {
213   CPlusPlusLanguage::CxxMethodName cpp_method{ConstString(full_name)};
214 
215   if (!cpp_method.IsValid())
216     return false;
217 
218   llvm::StringRef return_type = cpp_method.GetReturnType();
219   if (!return_type.empty()) {
220     out_stream.PutCString(return_type);
221     out_stream.PutChar(' ');
222   }
223 
224   out_stream.PutCString(cpp_method.GetScopeQualifiedName());
225   out_stream.PutChar('(');
226 
227   FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope);
228 
229   out_stream.PutChar(')');
230 
231   llvm::StringRef qualifiers = cpp_method.GetQualifiers();
232   if (!qualifiers.empty()) {
233     out_stream.PutChar(' ');
234     out_stream.PutCString(qualifiers);
235   }
236 
237   return true;
238 }
239 
240 static llvm::Expected<std::pair<llvm::StringRef, DemangledNameInfo>>
GetAndValidateInfo(const SymbolContext & sc)241 GetAndValidateInfo(const SymbolContext &sc) {
242   Mangled mangled = sc.GetPossiblyInlinedFunctionName();
243   if (!mangled)
244     return llvm::createStringError("Function does not have a mangled name.");
245 
246   auto demangled_name = mangled.GetDemangledName().GetStringRef();
247   if (demangled_name.empty())
248     return llvm::createStringError(
249         "Function '%s' does not have a demangled name.",
250         mangled.GetMangledName().AsCString(""));
251 
252   const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
253   if (!info)
254     return llvm::createStringError(
255         "Function '%s' does not have demangled info.", demangled_name.data());
256 
257   // Function without a basename is nonsense.
258   if (!info->hasBasename())
259     return llvm::createStringError(
260         "DemangledInfo for '%s does not have basename range.",
261         demangled_name.data());
262 
263   return std::make_pair(demangled_name, *info);
264 }
265 
266 static llvm::Expected<llvm::StringRef>
GetDemangledBasename(const SymbolContext & sc)267 GetDemangledBasename(const SymbolContext &sc) {
268   auto info_or_err = GetAndValidateInfo(sc);
269   if (!info_or_err)
270     return info_or_err.takeError();
271 
272   auto [demangled_name, info] = *info_or_err;
273 
274   return demangled_name.slice(info.BasenameRange.first,
275                               info.BasenameRange.second);
276 }
277 
278 static llvm::Expected<llvm::StringRef>
GetDemangledTemplateArguments(const SymbolContext & sc)279 GetDemangledTemplateArguments(const SymbolContext &sc) {
280   auto info_or_err = GetAndValidateInfo(sc);
281   if (!info_or_err)
282     return info_or_err.takeError();
283 
284   auto [demangled_name, info] = *info_or_err;
285 
286   if (info.ArgumentsRange.first < info.BasenameRange.second)
287     return llvm::createStringError("Arguments range for '%s' is invalid.",
288                                    demangled_name.data());
289 
290   return demangled_name.slice(info.BasenameRange.second,
291                               info.ArgumentsRange.first);
292 }
293 
294 static llvm::Expected<llvm::StringRef>
GetDemangledReturnTypeLHS(const SymbolContext & sc)295 GetDemangledReturnTypeLHS(const SymbolContext &sc) {
296   auto info_or_err = GetAndValidateInfo(sc);
297   if (!info_or_err)
298     return info_or_err.takeError();
299 
300   auto [demangled_name, info] = *info_or_err;
301 
302   if (info.ScopeRange.first >= demangled_name.size())
303     return llvm::createStringError(
304         "Scope range for '%s' LHS return type is invalid.",
305         demangled_name.data());
306 
307   return demangled_name.substr(0, info.ScopeRange.first);
308 }
309 
310 static llvm::Expected<llvm::StringRef>
GetDemangledFunctionQualifiers(const SymbolContext & sc)311 GetDemangledFunctionQualifiers(const SymbolContext &sc) {
312   auto info_or_err = GetAndValidateInfo(sc);
313   if (!info_or_err)
314     return info_or_err.takeError();
315 
316   auto [demangled_name, info] = *info_or_err;
317 
318   if (!info.hasQualifiers())
319     return llvm::createStringError("Qualifiers range for '%s' is invalid.",
320                                    demangled_name.data());
321 
322   return demangled_name.slice(info.QualifiersRange.first,
323                               info.QualifiersRange.second);
324 }
325 
326 static llvm::Expected<llvm::StringRef>
GetDemangledReturnTypeRHS(const SymbolContext & sc)327 GetDemangledReturnTypeRHS(const SymbolContext &sc) {
328   auto info_or_err = GetAndValidateInfo(sc);
329   if (!info_or_err)
330     return info_or_err.takeError();
331 
332   auto [demangled_name, info] = *info_or_err;
333 
334   if (info.QualifiersRange.first < info.ArgumentsRange.second)
335     return llvm::createStringError(
336         "Qualifiers range for '%s' RHS return type  is invalid.",
337         demangled_name.data());
338 
339   return demangled_name.slice(info.ArgumentsRange.second,
340                               info.QualifiersRange.first);
341 }
342 
343 static llvm::Expected<llvm::StringRef>
GetDemangledScope(const SymbolContext & sc)344 GetDemangledScope(const SymbolContext &sc) {
345   auto info_or_err = GetAndValidateInfo(sc);
346   if (!info_or_err)
347     return info_or_err.takeError();
348 
349   auto [demangled_name, info] = *info_or_err;
350 
351   if (!info.hasScope())
352     return llvm::createStringError("Scope range for '%s' is invalid.",
353                                    demangled_name.data());
354 
355   return demangled_name.slice(info.ScopeRange.first, info.ScopeRange.second);
356 }
357 
358 /// Handles anything printed after the FunctionEncoding ItaniumDemangle
359 /// node. Most notably the DotSUffix node.
360 static llvm::Expected<llvm::StringRef>
GetDemangledFunctionSuffix(const SymbolContext & sc)361 GetDemangledFunctionSuffix(const SymbolContext &sc) {
362   auto info_or_err = GetAndValidateInfo(sc);
363   if (!info_or_err)
364     return info_or_err.takeError();
365 
366   auto [demangled_name, info] = *info_or_err;
367 
368   if (!info.hasSuffix())
369     return llvm::createStringError("Suffix range for '%s' is invalid.",
370                                    demangled_name.data());
371 
372   return demangled_name.slice(info.SuffixRange.first, info.SuffixRange.second);
373 }
374 
PrintDemangledArgumentList(Stream & s,const SymbolContext & sc)375 static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
376   assert(sc.symbol);
377 
378   auto info_or_err = GetAndValidateInfo(sc);
379   if (!info_or_err) {
380     LLDB_LOG_ERROR(GetLog(LLDBLog::Language), info_or_err.takeError(),
381                    "Failed to handle ${{function.formatted-arguments}} "
382                    "frame-format variable: {0}");
383     return false;
384   }
385   auto [demangled_name, info] = *info_or_err;
386 
387   if (!info.hasArguments())
388     return false;
389 
390   s << demangled_name.slice(info.ArgumentsRange.first,
391                             info.ArgumentsRange.second);
392 
393   return true;
394 }
395 
TrySimplifiedParse()396 bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() {
397   // This method tries to parse simple method definitions which are presumably
398   // most comman in user programs. Definitions that can be parsed by this
399   // function don't have return types and templates in the name.
400   // A::B::C::fun(std::vector<T> &) const
401   size_t arg_start, arg_end;
402   llvm::StringRef full(m_full.GetCString());
403   llvm::StringRef parens("()", 2);
404   if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
405     m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
406     if (arg_end + 1 < full.size())
407       m_qualifiers = full.substr(arg_end + 1).ltrim();
408 
409     if (arg_start == 0)
410       return false;
411     size_t basename_end = arg_start;
412     size_t context_start = 0;
413     size_t context_end = full.rfind(':', basename_end);
414     if (context_end == llvm::StringRef::npos)
415       m_basename = full.substr(0, basename_end);
416     else {
417       if (context_start < context_end)
418         m_context = full.substr(context_start, context_end - 1 - context_start);
419       const size_t basename_begin = context_end + 1;
420       m_basename = full.substr(basename_begin, basename_end - basename_begin);
421     }
422 
423     if (IsTrivialBasename(m_basename)) {
424       return true;
425     } else {
426       // The C++ basename doesn't match our regular expressions so this can't
427       // be a valid C++ method, clear everything out and indicate an error
428       m_context = llvm::StringRef();
429       m_basename = llvm::StringRef();
430       m_arguments = llvm::StringRef();
431       m_qualifiers = llvm::StringRef();
432       m_return_type = llvm::StringRef();
433       return false;
434     }
435   }
436   return false;
437 }
438 
Parse()439 void CPlusPlusLanguage::CxxMethodName::Parse() {
440   if (!m_parsed && m_full) {
441     if (TrySimplifiedParse()) {
442       m_parse_error = false;
443     } else {
444       CPlusPlusNameParser parser(m_full.GetStringRef());
445       if (auto function = parser.ParseAsFunctionDefinition()) {
446         m_basename = function->name.basename;
447         m_context = function->name.context;
448         m_arguments = function->arguments;
449         m_qualifiers = function->qualifiers;
450         m_return_type = function->return_type;
451         m_parse_error = false;
452       } else {
453         m_parse_error = true;
454       }
455     }
456     if (m_context.empty()) {
457       m_scope_qualified = std::string(m_basename);
458     } else {
459       m_scope_qualified = m_context;
460       m_scope_qualified += "::";
461       m_scope_qualified += m_basename;
462     }
463     m_parsed = true;
464   }
465 }
466 
467 llvm::StringRef
GetBasenameNoTemplateParameters()468 CPlusPlusLanguage::CxxMethodName::GetBasenameNoTemplateParameters() {
469   llvm::StringRef basename = GetBasename();
470   size_t arg_start, arg_end;
471   llvm::StringRef parens("<>", 2);
472   if (ReverseFindMatchingChars(basename, parens, arg_start, arg_end))
473     return basename.substr(0, arg_start);
474 
475   return basename;
476 }
477 
ContainsPath(llvm::StringRef path)478 bool CPlusPlusLanguage::CxxMethodName::ContainsPath(llvm::StringRef path) {
479   if (!m_parsed)
480     Parse();
481 
482   // If we can't parse the incoming name, then just check that it contains path.
483   if (m_parse_error)
484     return m_full.GetStringRef().contains(path);
485 
486   llvm::StringRef identifier;
487   llvm::StringRef context;
488   std::string path_str = path.str();
489   bool success = CPlusPlusLanguage::ExtractContextAndIdentifier(
490       path_str.c_str(), context, identifier);
491   if (!success)
492     return m_full.GetStringRef().contains(path);
493 
494   // Basename may include template arguments.
495   // E.g.,
496   // GetBaseName(): func<int>
497   // identifier   : func
498   //
499   // ...but we still want to account for identifiers with template parameter
500   // lists, e.g., when users set breakpoints on template specializations.
501   //
502   // E.g.,
503   // GetBaseName(): func<uint32_t>
504   // identifier   : func<int32_t*>
505   //
506   // Try to match the basename with or without template parameters.
507   if (GetBasename() != identifier &&
508       GetBasenameNoTemplateParameters() != identifier)
509     return false;
510 
511   // Incoming path only had an identifier, so we match.
512   if (context.empty())
513     return true;
514   // Incoming path has context but this method does not, no match.
515   if (m_context.empty())
516     return false;
517 
518   llvm::StringRef haystack = m_context;
519   if (!haystack.consume_back(context))
520     return false;
521   if (haystack.empty() || !isalnum(haystack.back()))
522     return true;
523 
524   return false;
525 }
526 
DemangledNameContainsPath(llvm::StringRef path,ConstString demangled) const527 bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path,
528                                                   ConstString demangled) const {
529   CxxMethodName demangled_name(demangled);
530   return demangled_name.ContainsPath(path);
531 }
532 
ExtractContextAndIdentifier(const char * name,llvm::StringRef & context,llvm::StringRef & identifier)533 bool CPlusPlusLanguage::ExtractContextAndIdentifier(
534     const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
535   if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
536     return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
537                                                                   identifier);
538 
539   CPlusPlusNameParser parser(name);
540   if (auto full_name = parser.ParseAsFullName()) {
541     identifier = full_name->basename;
542     context = full_name->context;
543     return true;
544   }
545   return false;
546 }
547 
548 namespace {
549 class NodeAllocator {
550   llvm::BumpPtrAllocator Alloc;
551 
552 public:
reset()553   void reset() { Alloc.Reset(); }
554 
makeNode(Args &&...args)555   template <typename T, typename... Args> T *makeNode(Args &&...args) {
556     return new (Alloc.Allocate(sizeof(T), alignof(T)))
557         T(std::forward<Args>(args)...);
558   }
559 
allocateNodeArray(size_t sz)560   void *allocateNodeArray(size_t sz) {
561     return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
562                           alignof(llvm::itanium_demangle::Node *));
563   }
564 };
565 
566 template <typename Derived>
567 class ManglingSubstitutor
568     : public llvm::itanium_demangle::AbstractManglingParser<Derived,
569                                                             NodeAllocator> {
570   using Base =
571       llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
572 
573 public:
ManglingSubstitutor()574   ManglingSubstitutor() : Base(nullptr, nullptr) {}
575 
576   template <typename... Ts>
substitute(llvm::StringRef Mangled,Ts &&...Vals)577   ConstString substitute(llvm::StringRef Mangled, Ts &&...Vals) {
578     this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
579     return substituteImpl(Mangled);
580   }
581 
582 protected:
reset(llvm::StringRef Mangled)583   void reset(llvm::StringRef Mangled) {
584     Base::reset(Mangled.begin(), Mangled.end());
585     Written = Mangled.begin();
586     Result.clear();
587     Substituted = false;
588   }
589 
substituteImpl(llvm::StringRef Mangled)590   ConstString substituteImpl(llvm::StringRef Mangled) {
591     Log *log = GetLog(LLDBLog::Language);
592     if (this->parse() == nullptr) {
593       LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
594       return ConstString();
595     }
596     if (!Substituted)
597       return ConstString();
598 
599     // Append any trailing unmodified input.
600     appendUnchangedInput();
601     LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
602     return ConstString(Result);
603   }
604 
trySubstitute(llvm::StringRef From,llvm::StringRef To)605   void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
606     if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
607       return;
608 
609     // We found a match. Append unmodified input up to this point.
610     appendUnchangedInput();
611 
612     // And then perform the replacement.
613     Result += To;
614     Written += From.size();
615     Substituted = true;
616   }
617 
618 private:
619   /// Input character until which we have constructed the respective output
620   /// already.
621   const char *Written = "";
622 
623   llvm::SmallString<128> Result;
624 
625   /// Whether we have performed any substitutions.
626   bool Substituted = false;
627 
currentParserPos() const628   const char *currentParserPos() const { return this->First; }
629 
appendUnchangedInput()630   void appendUnchangedInput() {
631     Result +=
632         llvm::StringRef(Written, std::distance(Written, currentParserPos()));
633     Written = currentParserPos();
634   }
635 };
636 
637 /// Given a mangled function `Mangled`, replace all the primitive function type
638 /// arguments of `Search` with type `Replace`.
639 class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
640   llvm::StringRef Search;
641   llvm::StringRef Replace;
642 
643 public:
reset(llvm::StringRef Mangled,llvm::StringRef Search,llvm::StringRef Replace)644   void reset(llvm::StringRef Mangled, llvm::StringRef Search,
645              llvm::StringRef Replace) {
646     ManglingSubstitutor::reset(Mangled);
647     this->Search = Search;
648     this->Replace = Replace;
649   }
650 
parseType()651   llvm::itanium_demangle::Node *parseType() {
652     trySubstitute(Search, Replace);
653     return ManglingSubstitutor::parseType();
654   }
655 };
656 
657 class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
658 public:
659   llvm::itanium_demangle::Node *
parseCtorDtorName(llvm::itanium_demangle::Node * & SoFar,NameState * State)660   parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
661     trySubstitute("C1", "C2");
662     trySubstitute("D1", "D2");
663     return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
664   }
665 };
666 } // namespace
667 
GenerateAlternateFunctionManglings(const ConstString mangled_name) const668 std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
669     const ConstString mangled_name) const {
670   std::vector<ConstString> alternates;
671 
672   /// Get a basic set of alternative manglings for the given symbol `name`, by
673   /// making a few basic possible substitutions on basic types, storage duration
674   /// and `const`ness for the given symbol. The output parameter `alternates`
675   /// is filled with a best-guess, non-exhaustive set of different manglings
676   /// for the given name.
677 
678   // Maybe we're looking for a const symbol but the debug info told us it was
679   // non-const...
680   if (!strncmp(mangled_name.GetCString(), "_ZN", 3) &&
681       strncmp(mangled_name.GetCString(), "_ZNK", 4)) {
682     std::string fixed_scratch("_ZNK");
683     fixed_scratch.append(mangled_name.GetCString() + 3);
684     alternates.push_back(ConstString(fixed_scratch));
685   }
686 
687   // Maybe we're looking for a static symbol but we thought it was global...
688   if (!strncmp(mangled_name.GetCString(), "_Z", 2) &&
689       strncmp(mangled_name.GetCString(), "_ZL", 3)) {
690     std::string fixed_scratch("_ZL");
691     fixed_scratch.append(mangled_name.GetCString() + 2);
692     alternates.push_back(ConstString(fixed_scratch));
693   }
694 
695   TypeSubstitutor TS;
696   // `char` is implementation defined as either `signed` or `unsigned`.  As a
697   // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
698   // char, 'h'-unsigned char.  If we're looking for symbols with a signed char
699   // parameter, try finding matches which have the general case 'c'.
700   if (ConstString char_fixup =
701           TS.substitute(mangled_name.GetStringRef(), "a", "c"))
702     alternates.push_back(char_fixup);
703 
704   // long long parameter mangling 'x', may actually just be a long 'l' argument
705   if (ConstString long_fixup =
706           TS.substitute(mangled_name.GetStringRef(), "x", "l"))
707     alternates.push_back(long_fixup);
708 
709   // unsigned long long parameter mangling 'y', may actually just be unsigned
710   // long 'm' argument
711   if (ConstString ulong_fixup =
712           TS.substitute(mangled_name.GetStringRef(), "y", "m"))
713     alternates.push_back(ulong_fixup);
714 
715   if (ConstString ctor_fixup =
716           CtorDtorSubstitutor().substitute(mangled_name.GetStringRef()))
717     alternates.push_back(ctor_fixup);
718 
719   return alternates;
720 }
721 
FindBestAlternateFunctionMangledName(const Mangled mangled,const SymbolContext & sym_ctx) const722 ConstString CPlusPlusLanguage::FindBestAlternateFunctionMangledName(
723     const Mangled mangled, const SymbolContext &sym_ctx) const {
724   ConstString demangled = mangled.GetDemangledName();
725   if (!demangled)
726     return ConstString();
727 
728   CxxMethodName cpp_name(demangled);
729   std::string scope_qualified_name = cpp_name.GetScopeQualifiedName();
730 
731   if (!scope_qualified_name.size())
732     return ConstString();
733 
734   if (!sym_ctx.module_sp)
735     return ConstString();
736 
737   lldb_private::SymbolFile *sym_file = sym_ctx.module_sp->GetSymbolFile();
738   if (!sym_file)
739     return ConstString();
740 
741   std::vector<ConstString> alternates;
742   sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates);
743 
744   std::vector<ConstString> param_and_qual_matches;
745   std::vector<ConstString> param_matches;
746   for (size_t i = 0; i < alternates.size(); i++) {
747     ConstString alternate_mangled_name = alternates[i];
748     Mangled mangled(alternate_mangled_name);
749     ConstString demangled = mangled.GetDemangledName();
750 
751     CxxMethodName alternate_cpp_name(demangled);
752     if (!cpp_name.IsValid())
753       continue;
754 
755     if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments()) {
756       if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers())
757         param_and_qual_matches.push_back(alternate_mangled_name);
758       else
759         param_matches.push_back(alternate_mangled_name);
760     }
761   }
762 
763   if (param_and_qual_matches.size())
764     return param_and_qual_matches[0]; // It is assumed that there will be only
765                                       // one!
766   else if (param_matches.size())
767     return param_matches[0]; // Return one of them as a best match
768   else
769     return ConstString();
770 }
771 
LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp)772 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
773   if (!cpp_category_sp)
774     return;
775 
776   TypeSummaryImpl::Flags stl_summary_flags;
777   stl_summary_flags.SetCascades(true)
778       .SetSkipPointers(false)
779       .SetSkipReferences(false)
780       .SetDontShowChildren(true)
781       .SetDontShowValue(false)
782       .SetShowMembersOneLiner(false)
783       .SetHideItemNames(false);
784 
785   AddCXXSummary(cpp_category_sp,
786                 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
787                 "std::string summary provider", "^std::__[[:alnum:]]+::string$",
788                 stl_summary_flags, true);
789   AddCXXSummary(cpp_category_sp,
790                 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
791                 "std::string summary provider",
792                 "^std::__[[:alnum:]]+::basic_string<char, "
793                 "std::__[[:alnum:]]+::char_traits<char>,.*>$",
794                 stl_summary_flags, true);
795   AddCXXSummary(cpp_category_sp,
796                 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
797                 "std::string summary provider",
798                 "^std::__[[:alnum:]]+::basic_string<unsigned char, "
799                 "std::__[[:alnum:]]+::char_traits<unsigned char>,.*>$",
800                 stl_summary_flags, true);
801 
802   AddCXXSummary(cpp_category_sp,
803                 lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
804                 "std::u16string summary provider",
805                 "^std::__[[:alnum:]]+::basic_string<char16_t, "
806                 "std::__[[:alnum:]]+::char_traits<char16_t>,.*>$",
807                 stl_summary_flags, true);
808 
809   AddCXXSummary(cpp_category_sp,
810                 lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
811                 "std::u32string summary provider",
812                 "^std::__[[:alnum:]]+::basic_string<char32_t, "
813                 "std::__[[:alnum:]]+::char_traits<char32_t>,.*>$",
814                 stl_summary_flags, true);
815 
816   AddCXXSummary(cpp_category_sp,
817                 lldb_private::formatters::LibcxxWStringSummaryProvider,
818                 "std::wstring summary provider",
819                 "^std::__[[:alnum:]]+::wstring$", stl_summary_flags, true);
820   AddCXXSummary(cpp_category_sp,
821                 lldb_private::formatters::LibcxxWStringSummaryProvider,
822                 "std::wstring summary provider",
823                 "^std::__[[:alnum:]]+::basic_string<wchar_t, "
824                 "std::__[[:alnum:]]+::char_traits<wchar_t>,.*>$",
825                 stl_summary_flags, true);
826 
827   AddCXXSummary(cpp_category_sp,
828                 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
829                 "std::string_view summary provider",
830                 "^std::__[[:alnum:]]+::string_view$", stl_summary_flags, true);
831   AddCXXSummary(cpp_category_sp,
832                 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
833                 "std::string_view summary provider",
834                 "^std::__[[:alnum:]]+::basic_string_view<char, "
835                 "std::__[[:alnum:]]+::char_traits<char> >$",
836                 stl_summary_flags, true);
837   AddCXXSummary(cpp_category_sp,
838                 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
839                 "std::string_view summary provider",
840                 "^std::__[[:alnum:]]+::basic_string_view<unsigned char, "
841                 "std::__[[:alnum:]]+::char_traits<unsigned char> >$",
842                 stl_summary_flags, true);
843 
844   AddCXXSummary(cpp_category_sp,
845                 lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16,
846                 "std::u16string_view summary provider",
847                 "^std::__[[:alnum:]]+::basic_string_view<char16_t, "
848                 "std::__[[:alnum:]]+::char_traits<char16_t> >$",
849                 stl_summary_flags, true);
850 
851   AddCXXSummary(cpp_category_sp,
852                 lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32,
853                 "std::u32string_view summary provider",
854                 "^std::__[[:alnum:]]+::basic_string_view<char32_t, "
855                 "std::__[[:alnum:]]+::char_traits<char32_t> >$",
856                 stl_summary_flags, true);
857 
858   AddCXXSummary(cpp_category_sp,
859                 lldb_private::formatters::LibcxxWStringViewSummaryProvider,
860                 "std::wstring_view summary provider",
861                 "^std::__[[:alnum:]]+::wstring_view$", stl_summary_flags, true);
862   AddCXXSummary(cpp_category_sp,
863                 lldb_private::formatters::LibcxxWStringViewSummaryProvider,
864                 "std::wstring_view summary provider",
865                 "^std::__[[:alnum:]]+::basic_string_view<wchar_t, "
866                 "std::__[[:alnum:]]+::char_traits<wchar_t> >$",
867                 stl_summary_flags, true);
868 
869   SyntheticChildren::Flags stl_synth_flags;
870   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
871       false);
872   SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
873   stl_deref_flags.SetFrontEndWantsDereference();
874 
875   AddCXXSynthetic(
876       cpp_category_sp,
877       lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator,
878       "libc++ std::bitset synthetic children",
879       "^std::__[[:alnum:]]+::bitset<.+>$", stl_deref_flags, true);
880   AddCXXSynthetic(
881       cpp_category_sp,
882       lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
883       "libc++ std::vector synthetic children",
884       "^std::__[[:alnum:]]+::vector<.+>$", stl_deref_flags, true);
885   AddCXXSynthetic(
886       cpp_category_sp,
887       lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator,
888       "libc++ std::valarray synthetic children",
889       "^std::__[[:alnum:]]+::valarray<.+>$", stl_deref_flags, true);
890   AddCXXSynthetic(
891       cpp_category_sp,
892       lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator,
893       "libc++ std::slice_array synthetic children",
894       "^std::__[[:alnum:]]+::slice_array<.+>$", stl_deref_flags, true);
895   AddCXXSynthetic(
896       cpp_category_sp,
897       lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator,
898       "libc++ synthetic children for the valarray proxy arrays",
899       "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
900       stl_deref_flags, true);
901   AddCXXSynthetic(
902       cpp_category_sp,
903       lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
904       "libc++ std::forward_list synthetic children",
905       "^std::__[[:alnum:]]+::forward_list<.+>$", stl_synth_flags, true);
906   AddCXXSynthetic(
907       cpp_category_sp,
908       lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator,
909       "libc++ std::list synthetic children",
910       // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$"
911       // so that it does not clash with: "^std::(__cxx11::)?list<.+>$"
912       "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
913       "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$",
914       stl_deref_flags, true);
915   AddCXXSynthetic(
916       cpp_category_sp,
917       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
918       "libc++ std::map synthetic children", "^std::__[[:alnum:]]+::map<.+> >$",
919       stl_synth_flags, true);
920   AddCXXSynthetic(
921       cpp_category_sp,
922       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
923       "libc++ std::set synthetic children", "^std::__[[:alnum:]]+::set<.+> >$",
924       stl_deref_flags, true);
925   AddCXXSynthetic(
926       cpp_category_sp,
927       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
928       "libc++ std::multiset synthetic children",
929       "^std::__[[:alnum:]]+::multiset<.+> >$", stl_deref_flags, true);
930   AddCXXSynthetic(
931       cpp_category_sp,
932       lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
933       "libc++ std::multimap synthetic children",
934       "^std::__[[:alnum:]]+::multimap<.+> >$", stl_synth_flags, true);
935   AddCXXSynthetic(
936       cpp_category_sp,
937       lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator,
938       "libc++ std::unordered containers synthetic children",
939       "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
940       stl_synth_flags, true);
941   AddCXXSynthetic(
942       cpp_category_sp,
943       lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
944       "libc++ std::initializer_list synthetic children",
945       "^std::initializer_list<.+>$", stl_synth_flags, true);
946   AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator,
947                   "libc++ std::queue synthetic children",
948                   "^std::__[[:alnum:]]+::queue<.+>$", stl_synth_flags, true);
949   AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator,
950                   "libc++ std::tuple synthetic children",
951                   "^std::__[[:alnum:]]+::tuple<.*>$", stl_synth_flags, true);
952   AddCXXSynthetic(cpp_category_sp, LibcxxOptionalSyntheticFrontEndCreator,
953                   "libc++ std::optional synthetic children",
954                   "^std::__[[:alnum:]]+::optional<.+>$", stl_synth_flags, true);
955   AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator,
956                   "libc++ std::variant synthetic children",
957                   "^std::__[[:alnum:]]+::variant<.+>$", stl_synth_flags, true);
958   AddCXXSynthetic(
959       cpp_category_sp,
960       lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
961       "libc++ std::atomic synthetic children",
962       "^std::__[[:alnum:]]+::atomic<.+>$", stl_synth_flags, true);
963   AddCXXSynthetic(
964       cpp_category_sp,
965       lldb_private::formatters::LibcxxStdSpanSyntheticFrontEndCreator,
966       "libc++ std::span synthetic children", "^std::__[[:alnum:]]+::span<.+>$",
967       stl_deref_flags, true);
968   AddCXXSynthetic(
969       cpp_category_sp,
970       lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEndCreator,
971       "libc++ std::ranges::ref_view synthetic children",
972       "^std::__[[:alnum:]]+::ranges::ref_view<.+>$", stl_deref_flags, true);
973 
974   cpp_category_sp->AddTypeSynthetic(
975       "^std::__[[:alnum:]]+::deque<.+>$", eFormatterMatchRegex,
976       SyntheticChildrenSP(new ScriptedSyntheticChildren(
977           stl_synth_flags,
978           "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
979 
980   AddCXXSynthetic(
981       cpp_category_sp,
982       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
983       "shared_ptr synthetic children", "^std::__[[:alnum:]]+::shared_ptr<.+>$",
984       stl_synth_flags, true);
985 
986   static constexpr const char *const libcxx_std_unique_ptr_regex =
987       "^std::__[[:alnum:]]+::unique_ptr<.+>$";
988   AddCXXSynthetic(
989       cpp_category_sp,
990       lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator,
991       "unique_ptr synthetic children", libcxx_std_unique_ptr_regex,
992       stl_synth_flags, true);
993 
994   AddCXXSynthetic(
995       cpp_category_sp,
996       lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
997       "weak_ptr synthetic children", "^std::__[[:alnum:]]+::weak_ptr<.+>$",
998       stl_synth_flags, true);
999   AddCXXSummary(cpp_category_sp,
1000                 lldb_private::formatters::LibcxxFunctionSummaryProvider,
1001                 "libc++ std::function summary provider",
1002                 "^std::__[[:alnum:]]+::function<.+>$", stl_summary_flags, true);
1003 
1004   static constexpr const char *const libcxx_std_coroutine_handle_regex =
1005       "^std::__[[:alnum:]]+::coroutine_handle<.+>$";
1006   AddCXXSynthetic(
1007       cpp_category_sp,
1008       lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator,
1009       "coroutine_handle synthetic children", libcxx_std_coroutine_handle_regex,
1010       stl_deref_flags, true);
1011 
1012   stl_summary_flags.SetDontShowChildren(false);
1013   stl_summary_flags.SetSkipPointers(false);
1014   AddCXXSummary(cpp_category_sp,
1015                 lldb_private::formatters::ContainerSizeSummaryProvider,
1016                 "libc++ std::bitset summary provider",
1017                 "^std::__[[:alnum:]]+::bitset<.+>$", stl_summary_flags, true);
1018   AddCXXSummary(cpp_category_sp,
1019                 lldb_private::formatters::ContainerSizeSummaryProvider,
1020                 "libc++ std::vector summary provider",
1021                 "^std::__[[:alnum:]]+::vector<.+>$", stl_summary_flags, true);
1022   AddCXXSummary(cpp_category_sp,
1023                 lldb_private::formatters::ContainerSizeSummaryProvider,
1024                 "libc++ std::valarray summary provider",
1025                 "^std::__[[:alnum:]]+::valarray<.+>$", stl_summary_flags, true);
1026   AddCXXSummary(cpp_category_sp,
1027                 lldb_private::formatters::LibcxxStdSliceArraySummaryProvider,
1028                 "libc++ std::slice_array summary provider",
1029                 "^std::__[[:alnum:]]+::slice_array<.+>$", stl_summary_flags,
1030                 true);
1031   AddCXXSummary(cpp_category_sp,
1032                 lldb_private::formatters::ContainerSizeSummaryProvider,
1033                 "libc++ summary provider for the valarray proxy arrays",
1034                 "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
1035                 stl_summary_flags, true);
1036   AddCXXSummary(
1037       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1038       "libc++ std::list summary provider",
1039       "^std::__[[:alnum:]]+::forward_list<.+>$", stl_summary_flags, true);
1040   AddCXXSummary(
1041       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1042       "libc++ std::list summary provider",
1043       // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$"
1044       // so that it does not clash with: "^std::(__cxx11::)?list<.+>$"
1045       "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
1046       "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$",
1047       stl_summary_flags, true);
1048   AddCXXSummary(cpp_category_sp,
1049                 lldb_private::formatters::ContainerSizeSummaryProvider,
1050                 "libc++ std::map summary provider",
1051                 "^std::__[[:alnum:]]+::map<.+>$", stl_summary_flags, true);
1052   AddCXXSummary(cpp_category_sp,
1053                 lldb_private::formatters::ContainerSizeSummaryProvider,
1054                 "libc++ std::deque summary provider",
1055                 "^std::__[[:alnum:]]+::deque<.+>$", stl_summary_flags, true);
1056   AddCXXSummary(cpp_category_sp,
1057                 lldb_private::formatters::ContainerSizeSummaryProvider,
1058                 "libc++ std::queue summary provider",
1059                 "^std::__[[:alnum:]]+::queue<.+>$", stl_summary_flags, true);
1060   AddCXXSummary(cpp_category_sp,
1061                 lldb_private::formatters::ContainerSizeSummaryProvider,
1062                 "libc++ std::set summary provider",
1063                 "^std::__[[:alnum:]]+::set<.+>$", stl_summary_flags, true);
1064   AddCXXSummary(cpp_category_sp,
1065                 lldb_private::formatters::ContainerSizeSummaryProvider,
1066                 "libc++ std::multiset summary provider",
1067                 "^std::__[[:alnum:]]+::multiset<.+>$", stl_summary_flags, true);
1068   AddCXXSummary(cpp_category_sp,
1069                 lldb_private::formatters::ContainerSizeSummaryProvider,
1070                 "libc++ std::multimap summary provider",
1071                 "^std::__[[:alnum:]]+::multimap<.+>$", stl_summary_flags, true);
1072   AddCXXSummary(cpp_category_sp,
1073                 lldb_private::formatters::ContainerSizeSummaryProvider,
1074                 "libc++ std::unordered containers summary provider",
1075                 "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
1076                 stl_summary_flags, true);
1077   AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
1078                 "libc++ std::tuple summary provider",
1079                 "^std::__[[:alnum:]]+::tuple<.*>$", stl_summary_flags, true);
1080   AddCXXSummary(cpp_category_sp,
1081                 lldb_private::formatters::LibCxxAtomicSummaryProvider,
1082                 "libc++ std::atomic summary provider",
1083                 "^std::__[[:alnum:]]+::atomic<.+>$", stl_summary_flags, true);
1084   AddCXXSummary(cpp_category_sp,
1085                 lldb_private::formatters::GenericOptionalSummaryProvider,
1086                 "libc++ std::optional summary provider",
1087                 "^std::__[[:alnum:]]+::optional<.+>$", stl_summary_flags, true);
1088   AddCXXSummary(cpp_category_sp,
1089                 lldb_private::formatters::LibcxxVariantSummaryProvider,
1090                 "libc++ std::variant summary provider",
1091                 "^std::__[[:alnum:]]+::variant<.+>$", stl_summary_flags, true);
1092   AddCXXSummary(cpp_category_sp,
1093                 lldb_private::formatters::ContainerSizeSummaryProvider,
1094                 "libc++ std::span summary provider",
1095                 "^std::__[[:alnum:]]+::span<.+>$", stl_summary_flags, true);
1096 
1097   stl_summary_flags.SetSkipPointers(true);
1098 
1099   AddCXXSummary(cpp_category_sp,
1100                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
1101                 "libc++ std::shared_ptr summary provider",
1102                 "^std::__[[:alnum:]]+::shared_ptr<.+>$", stl_summary_flags,
1103                 true);
1104   AddCXXSummary(cpp_category_sp,
1105                 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
1106                 "libc++ std::weak_ptr summary provider",
1107                 "^std::__[[:alnum:]]+::weak_ptr<.+>$", stl_summary_flags, true);
1108   AddCXXSummary(cpp_category_sp,
1109                 lldb_private::formatters::LibcxxUniquePointerSummaryProvider,
1110                 "libc++ std::unique_ptr summary provider",
1111                 libcxx_std_unique_ptr_regex, stl_summary_flags, true);
1112 
1113   AddCXXSummary(cpp_category_sp,
1114                 lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
1115                 "libc++ std::coroutine_handle summary provider",
1116                 libcxx_std_coroutine_handle_regex, stl_summary_flags, true);
1117 
1118   AddCXXSynthetic(
1119       cpp_category_sp,
1120       lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator,
1121       "std::vector iterator synthetic children",
1122       "^std::__[[:alnum:]]+::__wrap_iter<.+>$", stl_synth_flags, true);
1123 
1124   AddCXXSynthetic(
1125       cpp_category_sp,
1126       lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
1127       "std::map iterator synthetic children",
1128       "^std::__[[:alnum:]]+::__map_(const_)?iterator<.+>$", stl_synth_flags,
1129       true);
1130 
1131   AddCXXSynthetic(cpp_category_sp,
1132                   lldb_private::formatters::
1133                       LibCxxUnorderedMapIteratorSyntheticFrontEndCreator,
1134                   "std::unordered_map iterator synthetic children",
1135                   "^std::__[[:alnum:]]+::__hash_map_(const_)?iterator<.+>$",
1136                   stl_synth_flags, true);
1137   // Chrono duration typedefs
1138   cpp_category_sp->AddTypeSummary(
1139       "^std::__[[:alnum:]]+::chrono::nanoseconds", eFormatterMatchRegex,
1140       TypeSummaryImplSP(new StringSummaryFormat(
1141           eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ns")));
1142   cpp_category_sp->AddTypeSummary(
1143       "^std::__[[:alnum:]]+::chrono::microseconds", eFormatterMatchRegex,
1144       TypeSummaryImplSP(new StringSummaryFormat(
1145           eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} µs")));
1146   cpp_category_sp->AddTypeSummary(
1147       "^std::__[[:alnum:]]+::chrono::milliseconds", eFormatterMatchRegex,
1148       TypeSummaryImplSP(new StringSummaryFormat(
1149           eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ms")));
1150   cpp_category_sp->AddTypeSummary(
1151       "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex,
1152       TypeSummaryImplSP(new StringSummaryFormat(
1153           eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s")));
1154   cpp_category_sp->AddTypeSummary(
1155       "^std::__[[:alnum:]]+::chrono::minutes", eFormatterMatchRegex,
1156       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1157                                                     eTypeOptionHideValue,
1158                                                 "${var.__rep_} min")));
1159   cpp_category_sp->AddTypeSummary(
1160       "^std::__[[:alnum:]]+::chrono::hours", eFormatterMatchRegex,
1161       TypeSummaryImplSP(new StringSummaryFormat(
1162           eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} h")));
1163 
1164   cpp_category_sp->AddTypeSummary(
1165       "^std::__[[:alnum:]]+::chrono::days", eFormatterMatchRegex,
1166       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1167                                                     eTypeOptionHideValue,
1168                                                 "${var.__rep_} days")));
1169   cpp_category_sp->AddTypeSummary(
1170       "^std::__[[:alnum:]]+::chrono::weeks", eFormatterMatchRegex,
1171       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1172                                                     eTypeOptionHideValue,
1173                                                 "${var.__rep_} weeks")));
1174   cpp_category_sp->AddTypeSummary(
1175       "^std::__[[:alnum:]]+::chrono::months", eFormatterMatchRegex,
1176       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1177                                                     eTypeOptionHideValue,
1178                                                 "${var.__rep_} months")));
1179   cpp_category_sp->AddTypeSummary(
1180       "^std::__[[:alnum:]]+::chrono::years", eFormatterMatchRegex,
1181       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1182                                                     eTypeOptionHideValue,
1183                                                 "${var.__rep_} years")));
1184   cpp_category_sp->AddTypeSummary(
1185       "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex,
1186       TypeSummaryImplSP(new StringSummaryFormat(
1187           eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s")));
1188 
1189   // Chrono time point types
1190 
1191   AddCXXSummary(cpp_category_sp,
1192                 lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider,
1193                 "libc++ std::chrono::sys_seconds summary provider",
1194                 "^std::__[[:alnum:]]+::chrono::time_point<"
1195                 "std::__[[:alnum:]]+::chrono::system_clock, "
1196                 "std::__[[:alnum:]]+::chrono::duration<.*, "
1197                 "std::__[[:alnum:]]+::ratio<1, 1> "
1198                 "> >$",
1199                 eTypeOptionHideChildren | eTypeOptionHideValue |
1200                     eTypeOptionCascade,
1201                 true);
1202   AddCXXSummary(cpp_category_sp,
1203                 lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider,
1204                 "libc++ std::chrono::sys_seconds summary provider",
1205                 "^std::__[[:alnum:]]+::chrono::time_point<"
1206                 "std::__[[:alnum:]]+::chrono::system_clock, "
1207                 "std::__[[:alnum:]]+::chrono::duration<int, "
1208                 "std::__[[:alnum:]]+::ratio<86400, 1> "
1209                 "> >$",
1210                 eTypeOptionHideChildren | eTypeOptionHideValue |
1211                     eTypeOptionCascade,
1212                 true);
1213 
1214   AddCXXSummary(
1215       cpp_category_sp,
1216       lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider,
1217       "libc++ std::chrono::local_seconds summary provider",
1218       "^std::__[[:alnum:]]+::chrono::time_point<"
1219       "std::__[[:alnum:]]+::chrono::local_t, "
1220       "std::__[[:alnum:]]+::chrono::duration<.*, "
1221       "std::__[[:alnum:]]+::ratio<1, 1> "
1222       "> >$",
1223       eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade,
1224       true);
1225   AddCXXSummary(cpp_category_sp,
1226                 lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider,
1227                 "libc++ std::chrono::local_seconds summary provider",
1228                 "^std::__[[:alnum:]]+::chrono::time_point<"
1229                 "std::__[[:alnum:]]+::chrono::local_t, "
1230                 "std::__[[:alnum:]]+::chrono::duration<int, "
1231                 "std::__[[:alnum:]]+::ratio<86400, 1> "
1232                 "> >$",
1233                 eTypeOptionHideChildren | eTypeOptionHideValue |
1234                     eTypeOptionCascade,
1235                 true);
1236 
1237   // Chrono calendar types
1238 
1239   cpp_category_sp->AddTypeSummary(
1240       "^std::__[[:alnum:]]+::chrono::day$", eFormatterMatchRegex,
1241       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1242                                                     eTypeOptionHideValue,
1243                                                 "day=${var.__d_%u}")));
1244 
1245   AddCXXSummary(cpp_category_sp,
1246                 lldb_private::formatters::LibcxxChronoMonthSummaryProvider,
1247                 "libc++ std::chrono::month summary provider",
1248                 "^std::__[[:alnum:]]+::chrono::month$",
1249                 eTypeOptionHideChildren | eTypeOptionHideValue, true);
1250 
1251   cpp_category_sp->AddTypeSummary(
1252       "^std::__[[:alnum:]]+::chrono::year$", eFormatterMatchRegex,
1253       TypeSummaryImplSP(new StringSummaryFormat(
1254           eTypeOptionHideChildren | eTypeOptionHideValue, "year=${var.__y_}")));
1255 
1256   AddCXXSummary(cpp_category_sp,
1257                 lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider,
1258                 "libc++ std::chrono::weekday summary provider",
1259                 "^std::__[[:alnum:]]+::chrono::weekday$",
1260                 eTypeOptionHideChildren | eTypeOptionHideValue, true);
1261 
1262   cpp_category_sp->AddTypeSummary(
1263       "^std::__[[:alnum:]]+::chrono::weekday_indexed$", eFormatterMatchRegex,
1264       TypeSummaryImplSP(new StringSummaryFormat(
1265           eTypeOptionHideChildren | eTypeOptionHideValue,
1266           "${var.__wd_} index=${var.__idx_%u}")));
1267 
1268   cpp_category_sp->AddTypeSummary(
1269       "^std::__[[:alnum:]]+::chrono::weekday_last$", eFormatterMatchRegex,
1270       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1271                                                     eTypeOptionHideValue,
1272                                                 "${var.__wd_} index=last")));
1273   cpp_category_sp->AddTypeSummary(
1274       "^std::__[[:alnum:]]+::chrono::month_day$", eFormatterMatchRegex,
1275       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1276                                                     eTypeOptionHideValue,
1277                                                 "${var.__m_} ${var.__d_}")));
1278   cpp_category_sp->AddTypeSummary(
1279       "^std::__[[:alnum:]]+::chrono::month_day_last$", eFormatterMatchRegex,
1280       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1281                                                     eTypeOptionHideValue,
1282                                                 "${var.__m_} day=last")));
1283 
1284   cpp_category_sp->AddTypeSummary(
1285       "^std::__[[:alnum:]]+::chrono::month_weekday$", eFormatterMatchRegex,
1286       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1287                                                     eTypeOptionHideValue,
1288                                                 "${var.__m_} ${var.__wdi_}")));
1289 
1290   cpp_category_sp->AddTypeSummary(
1291       "^std::__[[:alnum:]]+::chrono::month_weekday_last$", eFormatterMatchRegex,
1292       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1293                                                     eTypeOptionHideValue,
1294                                                 "${var.__m_} ${var.__wdl_}")));
1295 
1296   cpp_category_sp->AddTypeSummary(
1297       "^std::__[[:alnum:]]+::chrono::year_month$", eFormatterMatchRegex,
1298       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1299                                                     eTypeOptionHideValue,
1300                                                 "${var.__y_} ${var.__m_}")));
1301 
1302   AddCXXSummary(
1303       cpp_category_sp,
1304       lldb_private::formatters::LibcxxChronoYearMonthDaySummaryProvider,
1305       "libc++ std::chrono::year_month_day summary provider",
1306       "^std::__[[:alnum:]]+::chrono::year_month_day$",
1307       eTypeOptionHideChildren | eTypeOptionHideValue, true);
1308 
1309   cpp_category_sp->AddTypeSummary(
1310       "^std::__[[:alnum:]]+::chrono::year_month_day_last$",
1311       eFormatterMatchRegex,
1312       TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1313                                                     eTypeOptionHideValue,
1314                                                 "${var.__y_} ${var.__mdl_}")));
1315 
1316   cpp_category_sp->AddTypeSummary(
1317       "^std::__[[:alnum:]]+::chrono::year_month_weekday$", eFormatterMatchRegex,
1318       TypeSummaryImplSP(new StringSummaryFormat(
1319           eTypeOptionHideChildren | eTypeOptionHideValue,
1320           "${var.__y_} ${var.__m_} ${var.__wdi_}")));
1321 
1322   cpp_category_sp->AddTypeSummary(
1323       "^std::__[[:alnum:]]+::chrono::year_month_weekday_last$",
1324       eFormatterMatchRegex,
1325       TypeSummaryImplSP(new StringSummaryFormat(
1326           eTypeOptionHideChildren | eTypeOptionHideValue,
1327           "${var.__y_} ${var.__m_} ${var.__wdl_}")));
1328 }
1329 
RegisterStdStringSummaryProvider(const lldb::TypeCategoryImplSP & category_sp,llvm::StringRef string_ty,llvm::StringRef char_ty,lldb::TypeSummaryImplSP summary_sp)1330 static void RegisterStdStringSummaryProvider(
1331     const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty,
1332     llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) {
1333   auto makeSpecifier = [](llvm::StringRef name) {
1334     return std::make_shared<lldb_private::TypeNameSpecifierImpl>(
1335         name, eFormatterMatchExact);
1336   };
1337 
1338   category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
1339 
1340   category_sp->AddTypeSummary(
1341       makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
1342       summary_sp);
1343 
1344   category_sp->AddTypeSummary(
1345       std::make_shared<lldb_private::TypeNameSpecifierImpl>(
1346           llvm::formatv("^std::basic_string<{0}, ?std::char_traits<{0}>,.*>$",
1347                         char_ty)
1348               .str(),
1349           eFormatterMatchRegex),
1350       summary_sp);
1351 }
1352 
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1353 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1354   if (!cpp_category_sp)
1355     return;
1356 
1357   TypeSummaryImpl::Flags stl_summary_flags;
1358   stl_summary_flags.SetCascades(true)
1359       .SetSkipPointers(false)
1360       .SetSkipReferences(false)
1361       .SetDontShowChildren(true)
1362       .SetDontShowValue(false)
1363       .SetShowMembersOneLiner(false)
1364       .SetHideItemNames(false);
1365 
1366   lldb::TypeSummaryImplSP string_summary_sp(new CXXFunctionSummaryFormat(
1367       stl_summary_flags, LibStdcppStringSummaryProvider,
1368       "libstdc++ std::(w)string summary provider"));
1369   cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
1370                                   string_summary_sp);
1371   cpp_category_sp->AddTypeSummary(
1372       "^std::__cxx11::basic_string<char, std::char_traits<char>,.*>$",
1373       eFormatterMatchRegex, string_summary_sp);
1374   cpp_category_sp->AddTypeSummary("^std::__cxx11::basic_string<unsigned char, "
1375                                   "std::char_traits<unsigned char>,.*>$",
1376                                   eFormatterMatchRegex, string_summary_sp);
1377 
1378   cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact,
1379                                   string_summary_sp);
1380   cpp_category_sp->AddTypeSummary(
1381       "^std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>,.*>$",
1382       eFormatterMatchRegex, string_summary_sp);
1383 
1384   SyntheticChildren::Flags stl_synth_flags;
1385   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
1386       false);
1387   SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
1388   stl_deref_flags.SetFrontEndWantsDereference();
1389 
1390   cpp_category_sp->AddTypeSynthetic(
1391       "^std::(__debug::)?vector<.+>(( )?&)?$", eFormatterMatchRegex,
1392       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1393           stl_synth_flags,
1394           "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
1395   cpp_category_sp->AddTypeSynthetic(
1396       "^std::(__debug::)?map<.+> >(( )?&)?$", eFormatterMatchRegex,
1397       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1398           stl_synth_flags,
1399           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1400   cpp_category_sp->AddTypeSynthetic(
1401       "^std::(__debug)?deque<.+>(( )?&)?$", eFormatterMatchRegex,
1402       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1403           stl_deref_flags,
1404           "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider")));
1405   cpp_category_sp->AddTypeSynthetic(
1406       "^std::(__debug::)?set<.+> >(( )?&)?$", eFormatterMatchRegex,
1407       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1408           stl_deref_flags,
1409           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1410   cpp_category_sp->AddTypeSynthetic(
1411       "^std::(__debug::)?multimap<.+> >(( )?&)?$", eFormatterMatchRegex,
1412       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1413           stl_deref_flags,
1414           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1415   cpp_category_sp->AddTypeSynthetic(
1416       "^std::(__debug::)?multiset<.+> >(( )?&)?$", eFormatterMatchRegex,
1417       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1418           stl_deref_flags,
1419           "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1420   cpp_category_sp->AddTypeSynthetic(
1421       "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
1422       eFormatterMatchRegex,
1423       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1424           stl_deref_flags,
1425           "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")));
1426   cpp_category_sp->AddTypeSynthetic(
1427       "^std::((__debug::)?|(__cxx11::)?)list<.+>(( )?&)?$",
1428       eFormatterMatchRegex,
1429       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1430           stl_deref_flags,
1431           "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
1432   cpp_category_sp->AddTypeSynthetic(
1433       "^std::((__debug::)?|(__cxx11::)?)forward_list<.+>(( )?&)?$",
1434       eFormatterMatchRegex,
1435       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1436           stl_synth_flags,
1437           "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
1438   cpp_category_sp->AddTypeSynthetic(
1439       "^std::variant<.+>$", eFormatterMatchRegex,
1440       SyntheticChildrenSP(new ScriptedSyntheticChildren(
1441           stl_synth_flags,
1442           "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider")));
1443 
1444   stl_summary_flags.SetDontShowChildren(false);
1445   stl_summary_flags.SetSkipPointers(false);
1446 
1447   AddCXXSummary(
1448       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1449       "libstdc++ std::bitset summary provider",
1450       "^std::(__debug::)?bitset<.+>(( )?&)?$", stl_summary_flags, true);
1451 
1452   AddCXXSummary(
1453       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1454       "libstdc++ std::vector summary provider",
1455       "^std::(__debug::)?vector<.+>(( )?&)?$", stl_summary_flags, true);
1456 
1457   AddCXXSummary(
1458       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1459       "libstdc++ std::map summary provider",
1460       "^std::(__debug::)?map<.+> >(( )?&)?$", stl_summary_flags, true);
1461 
1462   AddCXXSummary(
1463       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1464       "libstdc++ std::set summary provider",
1465       "^std::(__debug::)?set<.+> >(( )?&)?$", stl_summary_flags, true);
1466 
1467   AddCXXSummary(
1468       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1469       "libstdc++ std::deque summary provider",
1470       "^std::(__debug::)?deque<.+>(( )?&)?$", stl_summary_flags, true);
1471 
1472   AddCXXSummary(
1473       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1474       "libstdc++ std::multimap summary provider",
1475       "^std::(__debug::)?multimap<.+> >(( )?&)?$", stl_summary_flags, true);
1476 
1477   AddCXXSummary(
1478       cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1479       "libstdc++ std::multiset summary provider",
1480       "^std::(__debug::)?multiset<.+> >(( )?&)?$", stl_summary_flags, true);
1481 
1482   AddCXXSummary(cpp_category_sp,
1483                 lldb_private::formatters::ContainerSizeSummaryProvider,
1484                 "libstdc++ std unordered container summary provider",
1485                 "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
1486                 stl_summary_flags, true);
1487 
1488   AddCXXSummary(cpp_category_sp,
1489                 lldb_private::formatters::ContainerSizeSummaryProvider,
1490                 "libstdc++ std::list summary provider",
1491                 "^std::((__debug::)?|(__cxx11::)?)list<.+>(( )?&)?$",
1492                 stl_summary_flags, true);
1493 
1494   AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
1495                 "libstdc++ std::tuple summary provider",
1496                 "^std::tuple<.*>(( )?&)?$", stl_summary_flags, true);
1497 
1498   cpp_category_sp->AddTypeSummary(
1499       "^std::((__debug::)?|(__cxx11::)?)forward_list<.+>(( )?&)?$",
1500       eFormatterMatchRegex,
1501       TypeSummaryImplSP(new ScriptSummaryFormat(
1502           stl_summary_flags,
1503           "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")));
1504   cpp_category_sp->AddTypeSummary(
1505       "^std::variant<.+>$", eFormatterMatchRegex,
1506       TypeSummaryImplSP(new ScriptSummaryFormat(
1507           stl_summary_flags,
1508           "lldb.formatters.cpp.gnu_libstdcpp.VariantSummaryProvider")));
1509 
1510   AddCXXSynthetic(
1511       cpp_category_sp,
1512       lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator,
1513       "std::vector iterator synthetic children",
1514       "^__gnu_cxx::__normal_iterator<.+>$", stl_synth_flags, true);
1515 
1516   AddCXXSynthetic(
1517       cpp_category_sp,
1518       lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator,
1519       "std::map iterator synthetic children",
1520       "^std::_Rb_tree_(const_)?iterator<.+>$", stl_synth_flags, true);
1521 
1522   AddCXXSynthetic(
1523       cpp_category_sp,
1524       lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
1525       "std::unique_ptr synthetic children", "^std::unique_ptr<.+>(( )?&)?$",
1526       stl_synth_flags, true);
1527   AddCXXSynthetic(
1528       cpp_category_sp,
1529       lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
1530       "std::tuple synthetic children", "^std::tuple<.*>(( )?&)?$",
1531       stl_synth_flags, true);
1532 
1533   static constexpr const char *const libstdcpp_std_coroutine_handle_regex =
1534       "^std::coroutine_handle<.+>(( )?&)?$";
1535   AddCXXSynthetic(
1536       cpp_category_sp,
1537       lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator,
1538       "std::coroutine_handle synthetic children",
1539       libstdcpp_std_coroutine_handle_regex, stl_deref_flags, true);
1540 
1541   AddCXXSynthetic(
1542       cpp_category_sp,
1543       lldb_private::formatters::LibStdcppBitsetSyntheticFrontEndCreator,
1544       "std::bitset synthetic child", "^std::(__debug::)?bitset<.+>(( )?&)?$",
1545       stl_deref_flags, true);
1546 
1547   AddCXXSynthetic(
1548       cpp_category_sp,
1549       lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator,
1550       "std::optional synthetic child", "^std::optional<.+>(( )?&)?$",
1551       stl_deref_flags, true);
1552 
1553   AddCXXSummary(cpp_category_sp,
1554                 lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
1555                 "libstdc++ std::coroutine_handle summary provider",
1556                 libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
1557   AddCXXSummary(cpp_category_sp,
1558                 lldb_private::formatters::GenericOptionalSummaryProvider,
1559                 "libstd++ std::optional summary provider",
1560                 "^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
1561 }
1562 
1563 static lldb_private::SyntheticChildrenFrontEnd *
GenericSmartPointerSyntheticFrontEndCreator(CXXSyntheticChildren * children,lldb::ValueObjectSP valobj_sp)1564 GenericSmartPointerSyntheticFrontEndCreator(CXXSyntheticChildren *children,
1565                                             lldb::ValueObjectSP valobj_sp) {
1566   if (!valobj_sp)
1567     return nullptr;
1568 
1569   if (IsMsvcStlSmartPointer(*valobj_sp))
1570     return MsvcStlSmartPointerSyntheticFrontEndCreator(valobj_sp);
1571   return LibStdcppSharedPtrSyntheticFrontEndCreator(children, valobj_sp);
1572 }
1573 
1574 static bool
GenericSmartPointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)1575 GenericSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
1576                                    const TypeSummaryOptions &options) {
1577   if (IsMsvcStlSmartPointer(valobj))
1578     return MsvcStlSmartPointerSummaryProvider(valobj, stream, options);
1579   return LibStdcppSmartPointerSummaryProvider(valobj, stream, options);
1580 }
1581 
1582 static lldb_private::SyntheticChildrenFrontEnd *
GenericUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren * children,lldb::ValueObjectSP valobj_sp)1583 GenericUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *children,
1584                                          lldb::ValueObjectSP valobj_sp) {
1585   if (!valobj_sp)
1586     return nullptr;
1587 
1588   if (IsMsvcStlUniquePtr(*valobj_sp))
1589     return MsvcStlUniquePtrSyntheticFrontEndCreator(valobj_sp);
1590   return LibStdcppUniquePtrSyntheticFrontEndCreator(children, valobj_sp);
1591 }
1592 
GenericUniquePtrSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)1593 static bool GenericUniquePtrSummaryProvider(ValueObject &valobj, Stream &stream,
1594                                             const TypeSummaryOptions &options) {
1595   if (IsMsvcStlUniquePtr(valobj))
1596     return MsvcStlUniquePtrSummaryProvider(valobj, stream, options);
1597   return LibStdcppUniquePointerSummaryProvider(valobj, stream, options);
1598 }
1599 
1600 /// Load formatters that are formatting types from more than one STL
LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1601 static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1602   if (!cpp_category_sp)
1603     return;
1604 
1605   TypeSummaryImpl::Flags stl_summary_flags;
1606   stl_summary_flags.SetCascades(true)
1607       .SetSkipPointers(false)
1608       .SetSkipReferences(false)
1609       .SetDontShowChildren(true)
1610       .SetDontShowValue(false)
1611       .SetShowMembersOneLiner(false)
1612       .SetHideItemNames(false);
1613   SyntheticChildren::Flags stl_synth_flags;
1614   stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
1615       false);
1616 
1617   using StringElementType = StringPrinter::StringElementType;
1618 
1619   RegisterStdStringSummaryProvider(
1620       cpp_category_sp, "std::string", "char",
1621       std::make_shared<CXXFunctionSummaryFormat>(
1622           stl_summary_flags,
1623           [](ValueObject &valobj, Stream &stream,
1624              const TypeSummaryOptions &options) {
1625             if (IsMsvcStlStringType(valobj))
1626               return MsvcStlStringSummaryProvider<StringElementType::ASCII>(
1627                   valobj, stream, options);
1628             return LibStdcppStringSummaryProvider(valobj, stream, options);
1629           },
1630           "MSVC STL/libstdc++ std::string summary provider"));
1631   RegisterStdStringSummaryProvider(
1632       cpp_category_sp, "std::wstring", "wchar_t",
1633       std::make_shared<CXXFunctionSummaryFormat>(
1634           stl_summary_flags,
1635           [](ValueObject &valobj, Stream &stream,
1636              const TypeSummaryOptions &options) {
1637             if (IsMsvcStlStringType(valobj))
1638               return MsvcStlWStringSummaryProvider(valobj, stream, options);
1639             return LibStdcppStringSummaryProvider(valobj, stream, options);
1640           },
1641           "MSVC STL/libstdc++ std::wstring summary provider"));
1642 
1643   stl_summary_flags.SetDontShowChildren(false);
1644   stl_summary_flags.SetSkipPointers(false);
1645 
1646   AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
1647                   "std::shared_ptr synthetic children",
1648                   "^std::shared_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1649   AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
1650                   "std::weak_ptr synthetic children",
1651                   "^std::weak_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1652   AddCXXSynthetic(cpp_category_sp, GenericUniquePtrSyntheticFrontEndCreator,
1653                   "std::unique_ptr synthetic children",
1654                   "^std::unique_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1655 
1656   AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
1657                 "MSVC STL/libstdc++ std::shared_ptr summary provider",
1658                 "^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1659   AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
1660                 "MSVC STL/libstdc++ std::weak_ptr summary provider",
1661                 "^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1662   AddCXXSummary(cpp_category_sp, GenericUniquePtrSummaryProvider,
1663                 "MSVC STL/libstdc++ std::unique_ptr summary provider",
1664                 "^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1665 }
1666 
LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1667 static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1668   if (!cpp_category_sp)
1669     return;
1670 
1671   TypeSummaryImpl::Flags stl_summary_flags;
1672   stl_summary_flags.SetCascades(true)
1673       .SetSkipPointers(false)
1674       .SetSkipReferences(false)
1675       .SetDontShowChildren(true)
1676       .SetDontShowValue(false)
1677       .SetShowMembersOneLiner(false)
1678       .SetHideItemNames(false);
1679 
1680   using StringElementType = StringPrinter::StringElementType;
1681 
1682   RegisterStdStringSummaryProvider(
1683       cpp_category_sp, "std::u8string", "char8_t",
1684       std::make_shared<CXXFunctionSummaryFormat>(
1685           stl_summary_flags,
1686           MsvcStlStringSummaryProvider<StringElementType::UTF8>,
1687           "MSVC STL std::u8string summary provider"));
1688   RegisterStdStringSummaryProvider(
1689       cpp_category_sp, "std::u16string", "char16_t",
1690       std::make_shared<CXXFunctionSummaryFormat>(
1691           stl_summary_flags,
1692           MsvcStlStringSummaryProvider<StringElementType::UTF16>,
1693           "MSVC STL std::u16string summary provider"));
1694   RegisterStdStringSummaryProvider(
1695       cpp_category_sp, "std::u32string", "char32_t",
1696       std::make_shared<CXXFunctionSummaryFormat>(
1697           stl_summary_flags,
1698           MsvcStlStringSummaryProvider<StringElementType::UTF32>,
1699           "MSVC STL std::u32string summary provider"));
1700 }
1701 
LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1702 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1703   if (!cpp_category_sp)
1704     return;
1705 
1706   TypeSummaryImpl::Flags string_flags;
1707   string_flags.SetCascades(true)
1708       .SetSkipPointers(true)
1709       .SetSkipReferences(false)
1710       .SetDontShowChildren(true)
1711       .SetDontShowValue(false)
1712       .SetShowMembersOneLiner(false)
1713       .SetHideItemNames(false);
1714 
1715   TypeSummaryImpl::Flags string_array_flags;
1716   string_array_flags.SetCascades(true)
1717       .SetSkipPointers(true)
1718       .SetSkipReferences(false)
1719       .SetDontShowChildren(true)
1720       .SetDontShowValue(true)
1721       .SetShowMembersOneLiner(false)
1722       .SetHideItemNames(false);
1723 
1724   AddCXXSummary(cpp_category_sp,
1725                 lldb_private::formatters::Char8StringSummaryProvider,
1726                 "char8_t * summary provider", "char8_t *", string_flags);
1727   AddCXXSummary(cpp_category_sp,
1728                 lldb_private::formatters::Char8StringSummaryProvider,
1729                 "char8_t [] summary provider", "char8_t ?\\[[0-9]+\\]",
1730                 string_array_flags, true);
1731 
1732   AddCXXSummary(cpp_category_sp,
1733                 lldb_private::formatters::Char16StringSummaryProvider,
1734                 "char16_t * summary provider", "char16_t *", string_flags);
1735   AddCXXSummary(cpp_category_sp,
1736                 lldb_private::formatters::Char16StringSummaryProvider,
1737                 "char16_t [] summary provider", "char16_t ?\\[[0-9]+\\]",
1738                 string_array_flags, true);
1739 
1740   AddCXXSummary(cpp_category_sp,
1741                 lldb_private::formatters::Char32StringSummaryProvider,
1742                 "char32_t * summary provider", "char32_t *", string_flags);
1743   AddCXXSummary(cpp_category_sp,
1744                 lldb_private::formatters::Char32StringSummaryProvider,
1745                 "char32_t [] summary provider", "char32_t ?\\[[0-9]+\\]",
1746                 string_array_flags, true);
1747 
1748   AddCXXSummary(cpp_category_sp,
1749                 lldb_private::formatters::WCharStringSummaryProvider,
1750                 "wchar_t * summary provider", "wchar_t *", string_flags);
1751   AddCXXSummary(cpp_category_sp,
1752                 lldb_private::formatters::WCharStringSummaryProvider,
1753                 "wchar_t * summary provider", "wchar_t ?\\[[0-9]+\\]",
1754                 string_array_flags, true);
1755 
1756   AddCXXSummary(cpp_category_sp,
1757                 lldb_private::formatters::Char16StringSummaryProvider,
1758                 "unichar * summary provider", "unichar *", string_flags);
1759 
1760   TypeSummaryImpl::Flags widechar_flags;
1761   widechar_flags.SetDontShowValue(true)
1762       .SetSkipPointers(true)
1763       .SetSkipReferences(false)
1764       .SetCascades(true)
1765       .SetDontShowChildren(true)
1766       .SetHideItemNames(true)
1767       .SetShowMembersOneLiner(false);
1768 
1769   AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char8SummaryProvider,
1770                 "char8_t summary provider", "char8_t", widechar_flags);
1771   AddCXXSummary(cpp_category_sp,
1772                 lldb_private::formatters::Char16SummaryProvider,
1773                 "char16_t summary provider", "char16_t", widechar_flags);
1774   AddCXXSummary(cpp_category_sp,
1775                 lldb_private::formatters::Char32SummaryProvider,
1776                 "char32_t summary provider", "char32_t", widechar_flags);
1777   AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider,
1778                 "wchar_t summary provider", "wchar_t", widechar_flags);
1779 
1780   AddCXXSummary(cpp_category_sp,
1781                 lldb_private::formatters::Char16SummaryProvider,
1782                 "unichar summary provider", "unichar", widechar_flags);
1783 }
1784 
GetTypeScavenger()1785 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() {
1786   class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger {
1787   public:
1788     CompilerType AdjustForInclusion(CompilerType &candidate) override {
1789       LanguageType lang_type(candidate.GetMinimumLanguage());
1790       if (!Language::LanguageIsC(lang_type) &&
1791           !Language::LanguageIsCPlusPlus(lang_type))
1792         return CompilerType();
1793       if (candidate.IsTypedefType())
1794         return candidate.GetTypedefedType();
1795       return candidate;
1796     }
1797   };
1798 
1799   return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
1800 }
1801 
GetFormatters()1802 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
1803   static llvm::once_flag g_initialize;
1804   static TypeCategoryImplSP g_category;
1805 
1806   llvm::call_once(g_initialize, [this]() -> void {
1807     DataVisualization::Categories::GetCategory(ConstString(GetPluginName()),
1808                                                g_category);
1809     if (g_category) {
1810       // NOTE: the libstdcpp formatters are loaded after libcxx formatters
1811       // because we don't want to the libcxx formatters to match the potential
1812       // `__debug` inline namespace that libstdcpp may use.
1813       // LLDB prioritizes the last loaded matching formatter.
1814       LoadLibCxxFormatters(g_category);
1815       LoadLibStdcppFormatters(g_category);
1816       LoadMsvcStlFormatters(g_category);
1817       LoadCommonStlFormatters(g_category);
1818       LoadSystemFormatters(g_category);
1819     }
1820   });
1821   return g_category;
1822 }
1823 
1824 HardcodedFormatters::HardcodedSummaryFinder
GetHardcodedSummaries()1825 CPlusPlusLanguage::GetHardcodedSummaries() {
1826   static llvm::once_flag g_initialize;
1827   static ConstString g_vectortypes("VectorTypes");
1828   static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
1829 
1830   llvm::call_once(g_initialize, []() -> void {
1831     g_formatters.push_back(
1832         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1833            FormatManager &) -> TypeSummaryImpl::SharedPointer {
1834           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1835               new CXXFunctionSummaryFormat(
1836                   TypeSummaryImpl::Flags(),
1837                   lldb_private::formatters::CXXFunctionPointerSummaryProvider,
1838                   "Function pointer summary provider"));
1839           if (CompilerType CT = valobj.GetCompilerType();
1840               CT.IsFunctionPointerType() || CT.IsMemberFunctionPointerType() ||
1841               valobj.GetValueType() == lldb::eValueTypeVTableEntry) {
1842             return formatter_sp;
1843           }
1844           return nullptr;
1845         });
1846     g_formatters.push_back(
1847         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1848            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1849           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1850               new CXXFunctionSummaryFormat(
1851                   TypeSummaryImpl::Flags()
1852                       .SetCascades(true)
1853                       .SetDontShowChildren(true)
1854                       .SetHideItemNames(true)
1855                       .SetShowMembersOneLiner(true)
1856                       .SetSkipPointers(true)
1857                       .SetSkipReferences(false),
1858                   lldb_private::formatters::VectorTypeSummaryProvider,
1859                   "vector_type pointer summary provider"));
1860           if (valobj.GetCompilerType().IsVectorType()) {
1861             if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1862               return formatter_sp;
1863           }
1864           return nullptr;
1865         });
1866     g_formatters.push_back(
1867         [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1868            FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1869           static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1870               new CXXFunctionSummaryFormat(
1871                   TypeSummaryImpl::Flags()
1872                       .SetCascades(true)
1873                       .SetDontShowChildren(true)
1874                       .SetHideItemNames(true)
1875                       .SetShowMembersOneLiner(true)
1876                       .SetSkipPointers(true)
1877                       .SetSkipReferences(false),
1878                   lldb_private::formatters::BlockPointerSummaryProvider,
1879                   "block pointer summary provider"));
1880           if (valobj.GetCompilerType().IsBlockPointerType()) {
1881             return formatter_sp;
1882           }
1883           return nullptr;
1884         });
1885   });
1886 
1887   return g_formatters;
1888 }
1889 
1890 HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics()1891 CPlusPlusLanguage::GetHardcodedSynthetics() {
1892   static llvm::once_flag g_initialize;
1893   static ConstString g_vectortypes("VectorTypes");
1894   static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
1895 
1896   llvm::call_once(g_initialize, []() -> void {
1897     g_formatters.push_back([](lldb_private::ValueObject &valobj,
1898                               lldb::DynamicValueType, FormatManager &fmt_mgr)
1899                                -> SyntheticChildren::SharedPointer {
1900       static CXXSyntheticChildren::SharedPointer formatter_sp(
1901           new CXXSyntheticChildren(
1902               SyntheticChildren::Flags()
1903                   .SetCascades(true)
1904                   .SetSkipPointers(true)
1905                   .SetSkipReferences(true)
1906                   .SetNonCacheable(true),
1907               "vector_type synthetic children",
1908               lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
1909       if (valobj.GetCompilerType().IsVectorType()) {
1910         if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1911           return formatter_sp;
1912       }
1913       return nullptr;
1914     });
1915     g_formatters.push_back([](lldb_private::ValueObject &valobj,
1916                               lldb::DynamicValueType, FormatManager &fmt_mgr)
1917                                -> SyntheticChildren::SharedPointer {
1918       static CXXSyntheticChildren::SharedPointer formatter_sp(
1919           new CXXSyntheticChildren(
1920               SyntheticChildren::Flags()
1921                   .SetCascades(true)
1922                   .SetSkipPointers(true)
1923                   .SetSkipReferences(true)
1924                   .SetNonCacheable(true),
1925               "block pointer synthetic children",
1926               lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
1927       if (valobj.GetCompilerType().IsBlockPointerType()) {
1928         return formatter_sp;
1929       }
1930       return nullptr;
1931     });
1932   });
1933 
1934   return g_formatters;
1935 }
1936 
IsNilReference(ValueObject & valobj)1937 bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) {
1938   if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) ||
1939       !valobj.IsPointerType())
1940     return false;
1941   bool canReadValue = true;
1942   bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
1943   return canReadValue && isZero;
1944 }
1945 
IsSourceFile(llvm::StringRef file_path) const1946 bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
1947   const auto suffixes = {".cpp", ".cxx", ".c++", ".cc",  ".c",
1948                          ".h",   ".hh",  ".hpp", ".hxx", ".h++"};
1949   for (auto suffix : suffixes) {
1950     if (file_path.ends_with_insensitive(suffix))
1951       return true;
1952   }
1953 
1954   // Check if we're in a STL path (where the files usually have no extension
1955   // that we could check for.
1956   return file_path.contains("/usr/include/c++/");
1957 }
1958 
GetFunctionVariableList(const SymbolContext & sc)1959 static VariableListSP GetFunctionVariableList(const SymbolContext &sc) {
1960   assert(sc.function);
1961 
1962   if (sc.block)
1963     if (Block *inline_block = sc.block->GetContainingInlinedBlock())
1964       return inline_block->GetBlockVariableList(true);
1965 
1966   return sc.function->GetBlock(true).GetBlockVariableList(true);
1967 }
1968 
PrintFunctionNameWithArgs(Stream & s,const ExecutionContext * exe_ctx,const SymbolContext & sc)1969 static bool PrintFunctionNameWithArgs(Stream &s,
1970                                       const ExecutionContext *exe_ctx,
1971                                       const SymbolContext &sc) {
1972   assert(sc.function);
1973 
1974   ExecutionContextScope *exe_scope =
1975       exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
1976 
1977   const char *cstr = sc.GetPossiblyInlinedFunctionName()
1978                          .GetName(Mangled::NamePreference::ePreferDemangled)
1979                          .AsCString();
1980   if (!cstr)
1981     return false;
1982 
1983   VariableList args;
1984   if (auto variable_list_sp = GetFunctionVariableList(sc))
1985     variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
1986                                                args);
1987 
1988   if (args.GetSize() > 0)
1989     return PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args);
1990 
1991   // FIXME: can we just unconditionally call PrettyPrintFunctionNameWithArgs?
1992   // It should be able to handle the "no arguments" case.
1993   s.PutCString(cstr);
1994 
1995   return true;
1996 }
1997 
GetFunctionDisplayName(const SymbolContext & sc,const ExecutionContext * exe_ctx,FunctionNameRepresentation representation,Stream & s)1998 bool CPlusPlusLanguage::GetFunctionDisplayName(
1999     const SymbolContext &sc, const ExecutionContext *exe_ctx,
2000     FunctionNameRepresentation representation, Stream &s) {
2001   switch (representation) {
2002   case FunctionNameRepresentation::eNameWithArgs: {
2003     // Print the function name with arguments in it
2004     if (sc.function)
2005       return PrintFunctionNameWithArgs(s, exe_ctx, sc);
2006 
2007     if (!sc.symbol)
2008       return false;
2009 
2010     const char *cstr = sc.symbol->GetName().AsCString(nullptr);
2011     if (!cstr)
2012       return false;
2013 
2014     s.PutCString(cstr);
2015 
2016     return true;
2017   }
2018   case FunctionNameRepresentation::eNameWithNoArgs:
2019   case FunctionNameRepresentation::eName:
2020     return false;
2021   }
2022 }
2023 
HandleFrameFormatVariable(const SymbolContext & sc,const ExecutionContext * exe_ctx,FormatEntity::Entry::Type type,Stream & s)2024 bool CPlusPlusLanguage::HandleFrameFormatVariable(
2025     const SymbolContext &sc, const ExecutionContext *exe_ctx,
2026     FormatEntity::Entry::Type type, Stream &s) {
2027   switch (type) {
2028   case FormatEntity::Entry::Type::FunctionScope: {
2029     auto scope_or_err = GetDemangledScope(sc);
2030     if (!scope_or_err) {
2031       LLDB_LOG_ERROR(
2032           GetLog(LLDBLog::Language), scope_or_err.takeError(),
2033           "Failed to handle ${{function.scope}} frame-format variable: {0}");
2034       return false;
2035     }
2036 
2037     s << *scope_or_err;
2038 
2039     return true;
2040   }
2041 
2042   case FormatEntity::Entry::Type::FunctionBasename: {
2043     auto name_or_err = GetDemangledBasename(sc);
2044     if (!name_or_err) {
2045       LLDB_LOG_ERROR(
2046           GetLog(LLDBLog::Language), name_or_err.takeError(),
2047           "Failed to handle ${{function.basename}} frame-format variable: {0}");
2048       return false;
2049     }
2050 
2051     s << *name_or_err;
2052 
2053     return true;
2054   }
2055 
2056   case FormatEntity::Entry::Type::FunctionTemplateArguments: {
2057     auto template_args_or_err = GetDemangledTemplateArguments(sc);
2058     if (!template_args_or_err) {
2059       LLDB_LOG_ERROR(GetLog(LLDBLog::Language),
2060                      template_args_or_err.takeError(),
2061                      "Failed to handle ${{function.template-arguments}} "
2062                      "frame-format variable: {0}");
2063       return false;
2064     }
2065 
2066     s << *template_args_or_err;
2067 
2068     return true;
2069   }
2070 
2071   case FormatEntity::Entry::Type::FunctionFormattedArguments: {
2072     // This ensures we print the arguments even when no debug-info is available.
2073     //
2074     // FIXME: we should have a Entry::Type::FunctionArguments and
2075     // use it in the plugin.cplusplus.display.function-name-format
2076     // once we have a "fallback operator" in the frame-format language.
2077     if (!sc.function && sc.symbol)
2078       return PrintDemangledArgumentList(s, sc);
2079 
2080     VariableList args;
2081     if (auto variable_list_sp = GetFunctionVariableList(sc))
2082       variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
2083                                                  args);
2084 
2085     ExecutionContextScope *exe_scope =
2086         exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
2087 
2088     s << '(';
2089     FormatEntity::PrettyPrintFunctionArguments(s, args, exe_scope);
2090     s << ')';
2091 
2092     return true;
2093   }
2094   case FormatEntity::Entry::Type::FunctionReturnRight: {
2095     auto return_rhs_or_err = GetDemangledReturnTypeRHS(sc);
2096     if (!return_rhs_or_err) {
2097       LLDB_LOG_ERROR(GetLog(LLDBLog::Language), return_rhs_or_err.takeError(),
2098                      "Failed to handle ${{function.return-right}} frame-format "
2099                      "variable: {0}");
2100       return false;
2101     }
2102 
2103     s << *return_rhs_or_err;
2104 
2105     return true;
2106   }
2107   case FormatEntity::Entry::Type::FunctionReturnLeft: {
2108     auto return_lhs_or_err = GetDemangledReturnTypeLHS(sc);
2109     if (!return_lhs_or_err) {
2110       LLDB_LOG_ERROR(GetLog(LLDBLog::Language), return_lhs_or_err.takeError(),
2111                      "Failed to handle ${{function.return-left}} frame-format "
2112                      "variable: {0}");
2113       return false;
2114     }
2115 
2116     s << *return_lhs_or_err;
2117 
2118     return true;
2119   }
2120   case FormatEntity::Entry::Type::FunctionQualifiers: {
2121     auto quals_or_err = GetDemangledFunctionQualifiers(sc);
2122     if (!quals_or_err) {
2123       LLDB_LOG_ERROR(GetLog(LLDBLog::Language), quals_or_err.takeError(),
2124                      "Failed to handle ${{function.qualifiers}} frame-format "
2125                      "variable: {0}");
2126       return false;
2127     }
2128 
2129     s << *quals_or_err;
2130 
2131     return true;
2132   }
2133   case FormatEntity::Entry::Type::FunctionSuffix: {
2134     auto suffix_or_err = GetDemangledFunctionSuffix(sc);
2135     if (!suffix_or_err) {
2136       LLDB_LOG_ERROR(
2137           GetLog(LLDBLog::Language), suffix_or_err.takeError(),
2138           "Failed to handle ${{function.suffix}} frame-format variable: {0}");
2139       return false;
2140     }
2141 
2142     s << *suffix_or_err;
2143 
2144     return true;
2145   }
2146   default:
2147     return false;
2148   }
2149 }
2150 
2151 #define LLDB_PROPERTIES_language_cplusplus
2152 #include "LanguageCPlusPlusProperties.inc"
2153 
2154 enum {
2155 #define LLDB_PROPERTIES_language_cplusplus
2156 #include "LanguageCPlusPlusPropertiesEnum.inc"
2157 };
2158 
2159 namespace {
2160 class PluginProperties : public Properties {
2161 public:
GetSettingName()2162   static llvm::StringRef GetSettingName() { return "display"; }
2163 
PluginProperties()2164   PluginProperties() {
2165     m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
2166     m_collection_sp->Initialize(g_language_cplusplus_properties);
2167   }
2168 
GetFunctionNameFormat() const2169   FormatEntity::Entry GetFunctionNameFormat() const {
2170     return GetPropertyAtIndexAs<FormatEntity::Entry>(
2171         ePropertyFunctionNameFormat, {});
2172   }
2173 };
2174 } // namespace
2175 
GetGlobalPluginProperties()2176 static PluginProperties &GetGlobalPluginProperties() {
2177   static PluginProperties g_settings;
2178   return g_settings;
2179 }
2180 
GetFunctionNameFormat() const2181 FormatEntity::Entry CPlusPlusLanguage::GetFunctionNameFormat() const {
2182   return GetGlobalPluginProperties().GetFunctionNameFormat();
2183 }
2184 
DebuggerInitialize(Debugger & debugger)2185 void CPlusPlusLanguage::DebuggerInitialize(Debugger &debugger) {
2186   if (!PluginManager::GetSettingForCPlusPlusLanguagePlugin(
2187           debugger, PluginProperties::GetSettingName())) {
2188     PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
2189         debugger, GetGlobalPluginProperties().GetValueProperties(),
2190         "Properties for the CPlusPlus language plug-in.",
2191         /*is_global_property=*/true);
2192   }
2193 }
2194