1 //===-- CPlusPlusLanguage.cpp -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "CPlusPlusLanguage.h" 11 12 // C Includes 13 #include <cctype> 14 #include <cstring> 15 16 // C++ Includes 17 #include <functional> 18 #include <memory> 19 #include <mutex> 20 #include <set> 21 22 // Other libraries and framework includes 23 #include "llvm/ADT/StringRef.h" 24 #include "llvm/Demangle/Demangle.h" 25 26 // Project includes 27 #include "lldb/Core/PluginManager.h" 28 #include "lldb/Core/UniqueCStringMap.h" 29 #include "lldb/DataFormatters/CXXFunctionPointer.h" 30 #include "lldb/DataFormatters/DataVisualization.h" 31 #include "lldb/DataFormatters/FormattersHelpers.h" 32 #include "lldb/DataFormatters/VectorType.h" 33 #include "lldb/Utility/ConstString.h" 34 #include "lldb/Utility/Log.h" 35 #include "lldb/Utility/RegularExpression.h" 36 37 #include "BlockPointer.h" 38 #include "CPlusPlusNameParser.h" 39 #include "CxxStringTypes.h" 40 #include "LibCxx.h" 41 #include "LibCxxAtomic.h" 42 #include "LibCxxVariant.h" 43 #include "LibStdcpp.h" 44 #include "MSVCUndecoratedNameParser.h" 45 46 using namespace lldb; 47 using namespace lldb_private; 48 using namespace lldb_private::formatters; 49 50 void CPlusPlusLanguage::Initialize() { 51 PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language", 52 CreateInstance); 53 } 54 55 void CPlusPlusLanguage::Terminate() { 56 PluginManager::UnregisterPlugin(CreateInstance); 57 } 58 59 lldb_private::ConstString CPlusPlusLanguage::GetPluginNameStatic() { 60 static ConstString g_name("cplusplus"); 61 return g_name; 62 } 63 64 //------------------------------------------------------------------ 65 // PluginInterface protocol 66 //------------------------------------------------------------------ 67 68 lldb_private::ConstString CPlusPlusLanguage::GetPluginName() { 69 return GetPluginNameStatic(); 70 } 71 72 uint32_t CPlusPlusLanguage::GetPluginVersion() { return 1; } 73 74 //------------------------------------------------------------------ 75 // Static Functions 76 //------------------------------------------------------------------ 77 78 Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) { 79 if (Language::LanguageIsCPlusPlus(language)) 80 return new CPlusPlusLanguage(); 81 return nullptr; 82 } 83 84 void CPlusPlusLanguage::MethodName::Clear() { 85 m_full.Clear(); 86 m_basename = llvm::StringRef(); 87 m_context = llvm::StringRef(); 88 m_arguments = llvm::StringRef(); 89 m_qualifiers = llvm::StringRef(); 90 m_parsed = false; 91 m_parse_error = false; 92 } 93 94 static bool ReverseFindMatchingChars(const llvm::StringRef &s, 95 const llvm::StringRef &left_right_chars, 96 size_t &left_pos, size_t &right_pos, 97 size_t pos = llvm::StringRef::npos) { 98 assert(left_right_chars.size() == 2); 99 left_pos = llvm::StringRef::npos; 100 const char left_char = left_right_chars[0]; 101 const char right_char = left_right_chars[1]; 102 pos = s.find_last_of(left_right_chars, pos); 103 if (pos == llvm::StringRef::npos || s[pos] == left_char) 104 return false; 105 right_pos = pos; 106 uint32_t depth = 1; 107 while (pos > 0 && depth > 0) { 108 pos = s.find_last_of(left_right_chars, pos); 109 if (pos == llvm::StringRef::npos) 110 return false; 111 if (s[pos] == left_char) { 112 if (--depth == 0) { 113 left_pos = pos; 114 return left_pos < right_pos; 115 } 116 } else if (s[pos] == right_char) { 117 ++depth; 118 } 119 } 120 return false; 121 } 122 123 static bool IsTrivialBasename(const llvm::StringRef &basename) { 124 // Check that the basename matches with the following regular expression 125 // "^~?([A-Za-z_][A-Za-z_0-9]*)$" We are using a hand written implementation 126 // because it is significantly more efficient then using the general purpose 127 // regular expression library. 128 size_t idx = 0; 129 if (basename.size() > 0 && basename[0] == '~') 130 idx = 1; 131 132 if (basename.size() <= idx) 133 return false; // Empty string or "~" 134 135 if (!std::isalpha(basename[idx]) && basename[idx] != '_') 136 return false; // First charater (after removing the possible '~'') isn't in 137 // [A-Za-z_] 138 139 // Read all characters matching [A-Za-z_0-9] 140 ++idx; 141 while (idx < basename.size()) { 142 if (!std::isalnum(basename[idx]) && basename[idx] != '_') 143 break; 144 ++idx; 145 } 146 147 // We processed all characters. It is a vaild basename. 148 if (idx == basename.size()) 149 return true; 150 151 return false; 152 } 153 154 bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() { 155 // This method tries to parse simple method definitions which are presumably 156 // most comman in user programs. Definitions that can be parsed by this 157 // function don't have return types and templates in the name. 158 // A::B::C::fun(std::vector<T> &) const 159 size_t arg_start, arg_end; 160 llvm::StringRef full(m_full.GetCString()); 161 llvm::StringRef parens("()", 2); 162 if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) { 163 m_arguments = full.substr(arg_start, arg_end - arg_start + 1); 164 if (arg_end + 1 < full.size()) 165 m_qualifiers = full.substr(arg_end + 1).ltrim(); 166 167 if (arg_start == 0) 168 return false; 169 size_t basename_end = arg_start; 170 size_t context_start = 0; 171 size_t context_end = full.rfind(':', basename_end); 172 if (context_end == llvm::StringRef::npos) 173 m_basename = full.substr(0, basename_end); 174 else { 175 if (context_start < context_end) 176 m_context = full.substr(context_start, context_end - 1 - context_start); 177 const size_t basename_begin = context_end + 1; 178 m_basename = full.substr(basename_begin, basename_end - basename_begin); 179 } 180 181 if (IsTrivialBasename(m_basename)) { 182 return true; 183 } else { 184 // The C++ basename doesn't match our regular expressions so this can't 185 // be a valid C++ method, clear everything out and indicate an error 186 m_context = llvm::StringRef(); 187 m_basename = llvm::StringRef(); 188 m_arguments = llvm::StringRef(); 189 m_qualifiers = llvm::StringRef(); 190 return false; 191 } 192 } 193 return false; 194 } 195 196 void CPlusPlusLanguage::MethodName::Parse() { 197 if (!m_parsed && m_full) { 198 if (TrySimplifiedParse()) { 199 m_parse_error = false; 200 } else { 201 CPlusPlusNameParser parser(m_full.GetStringRef()); 202 if (auto function = parser.ParseAsFunctionDefinition()) { 203 m_basename = function.getValue().name.basename; 204 m_context = function.getValue().name.context; 205 m_arguments = function.getValue().arguments; 206 m_qualifiers = function.getValue().qualifiers; 207 m_parse_error = false; 208 } else { 209 m_parse_error = true; 210 } 211 } 212 m_parsed = true; 213 } 214 } 215 216 llvm::StringRef CPlusPlusLanguage::MethodName::GetBasename() { 217 if (!m_parsed) 218 Parse(); 219 return m_basename; 220 } 221 222 llvm::StringRef CPlusPlusLanguage::MethodName::GetContext() { 223 if (!m_parsed) 224 Parse(); 225 return m_context; 226 } 227 228 llvm::StringRef CPlusPlusLanguage::MethodName::GetArguments() { 229 if (!m_parsed) 230 Parse(); 231 return m_arguments; 232 } 233 234 llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() { 235 if (!m_parsed) 236 Parse(); 237 return m_qualifiers; 238 } 239 240 std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() { 241 if (!m_parsed) 242 Parse(); 243 if (m_context.empty()) 244 return m_basename; 245 246 std::string res; 247 res += m_context; 248 res += "::"; 249 res += m_basename; 250 return res; 251 } 252 253 bool CPlusPlusLanguage::IsCPPMangledName(const char *name) { 254 // FIXME!! we should really run through all the known C++ Language plugins 255 // and ask each one if this is a C++ mangled name 256 257 if (name == nullptr) 258 return false; 259 260 // MSVC style mangling 261 if (name[0] == '?') 262 return true; 263 264 return (name[0] != '\0' && name[0] == '_' && name[1] == 'Z'); 265 } 266 267 bool CPlusPlusLanguage::ExtractContextAndIdentifier( 268 const char *name, llvm::StringRef &context, llvm::StringRef &identifier) { 269 if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name)) 270 return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context, 271 identifier); 272 273 CPlusPlusNameParser parser(name); 274 if (auto full_name = parser.ParseAsFullName()) { 275 identifier = full_name.getValue().basename; 276 context = full_name.getValue().context; 277 return true; 278 } 279 return false; 280 } 281 282 /// Given a mangled function `mangled`, replace all the primitive function type 283 /// arguments of `search` with type `replace`. 284 static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled, 285 llvm::StringRef search, 286 llvm::StringRef replace) { 287 class PrimitiveParmSubs { 288 llvm::StringRef mangled; 289 llvm::StringRef search; 290 llvm::StringRef replace; 291 ptrdiff_t read_pos; 292 std::string output; 293 std::back_insert_iterator<std::string> writer; 294 295 public: 296 PrimitiveParmSubs(llvm::StringRef m, llvm::StringRef s, llvm::StringRef r) 297 : mangled(m), search(s), replace(r), read_pos(0), 298 writer(std::back_inserter(output)) {} 299 300 void Substitute(llvm::StringRef tail) { 301 assert(tail.data() >= mangled.data() && 302 tail.data() < mangled.data() + mangled.size() && 303 "tail must point into range of mangled"); 304 305 if (tail.startswith(search)) { 306 auto reader = mangled.begin() + read_pos; 307 ptrdiff_t read_len = tail.data() - (mangled.data() + read_pos); 308 309 // First write the unmatched part of the original. Then write the 310 // replacement string. Finally skip the search string in the original. 311 writer = std::copy(reader, reader + read_len, writer); 312 writer = std::copy(replace.begin(), replace.end(), writer); 313 read_pos += read_len + search.size(); 314 } 315 } 316 317 ConstString Finalize() { 318 // If we did a substitution, write the remaining part of the original. 319 if (read_pos > 0) { 320 writer = std::copy(mangled.begin() + read_pos, mangled.end(), writer); 321 read_pos = mangled.size(); 322 } 323 324 return ConstString(output); 325 } 326 327 static void Callback(void *context, const char *match) { 328 ((PrimitiveParmSubs *)context)->Substitute(llvm::StringRef(match)); 329 } 330 }; 331 332 // The demangler will call back for each instance of a primitive type, 333 // allowing us to perform substitution 334 PrimitiveParmSubs parmSubs(mangled, search, replace); 335 assert(mangled.data()[mangled.size()] == '\0' && "Expect C-String"); 336 bool err = llvm::itaniumFindTypesInMangledName(mangled.data(), &parmSubs, 337 PrimitiveParmSubs::Callback); 338 ConstString result = parmSubs.Finalize(); 339 340 if (Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)) { 341 if (err) 342 LLDB_LOG(log, "Failed to substitute mangling in {0}", mangled); 343 else if (result) 344 LLDB_LOG(log, "Substituted mangling {0} -> {1}", mangled, result); 345 } 346 347 return result; 348 } 349 350 uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings( 351 const ConstString mangled_name, std::set<ConstString> &alternates) { 352 const auto start_size = alternates.size(); 353 /// Get a basic set of alternative manglings for the given symbol `name`, by 354 /// making a few basic possible substitutions on basic types, storage duration 355 /// and `const`ness for the given symbol. The output parameter `alternates` 356 /// is filled with a best-guess, non-exhaustive set of different manglings 357 /// for the given name. 358 359 // Maybe we're looking for a const symbol but the debug info told us it was 360 // non-const... 361 if (!strncmp(mangled_name.GetCString(), "_ZN", 3) && 362 strncmp(mangled_name.GetCString(), "_ZNK", 4)) { 363 std::string fixed_scratch("_ZNK"); 364 fixed_scratch.append(mangled_name.GetCString() + 3); 365 alternates.insert(ConstString(fixed_scratch)); 366 } 367 368 // Maybe we're looking for a static symbol but we thought it was global... 369 if (!strncmp(mangled_name.GetCString(), "_Z", 2) && 370 strncmp(mangled_name.GetCString(), "_ZL", 3)) { 371 std::string fixed_scratch("_ZL"); 372 fixed_scratch.append(mangled_name.GetCString() + 2); 373 alternates.insert(ConstString(fixed_scratch)); 374 } 375 376 // `char` is implementation defined as either `signed` or `unsigned`. As a 377 // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed 378 // char, 'h'-unsigned char. If we're looking for symbols with a signed char 379 // parameter, try finding matches which have the general case 'c'. 380 if (ConstString char_fixup = 381 SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "a", "c")) 382 alternates.insert(char_fixup); 383 384 // long long parameter mangling 'x', may actually just be a long 'l' argument 385 if (ConstString long_fixup = 386 SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "x", "l")) 387 alternates.insert(long_fixup); 388 389 // unsigned long long parameter mangling 'y', may actually just be unsigned 390 // long 'm' argument 391 if (ConstString ulong_fixup = 392 SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "y", "m")) 393 alternates.insert(ulong_fixup); 394 395 return alternates.size() - start_size; 396 } 397 398 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 399 if (!cpp_category_sp) 400 return; 401 402 TypeSummaryImpl::Flags stl_summary_flags; 403 stl_summary_flags.SetCascades(true) 404 .SetSkipPointers(false) 405 .SetSkipReferences(false) 406 .SetDontShowChildren(true) 407 .SetDontShowValue(true) 408 .SetShowMembersOneLiner(false) 409 .SetHideItemNames(false); 410 411 #ifndef LLDB_DISABLE_PYTHON 412 lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat( 413 stl_summary_flags, 414 lldb_private::formatters::LibcxxStringSummaryProviderASCII, 415 "std::string summary provider")); 416 lldb::TypeSummaryImplSP std_stringu16_summary_sp(new CXXFunctionSummaryFormat( 417 stl_summary_flags, 418 lldb_private::formatters::LibcxxStringSummaryProviderUTF16, 419 "std::u16string summary provider")); 420 lldb::TypeSummaryImplSP std_stringu32_summary_sp(new CXXFunctionSummaryFormat( 421 stl_summary_flags, 422 lldb_private::formatters::LibcxxStringSummaryProviderUTF32, 423 "std::u32string summary provider")); 424 lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat( 425 stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, 426 "std::wstring summary provider")); 427 428 cpp_category_sp->GetTypeSummariesContainer()->Add( 429 ConstString("std::__1::string"), std_string_summary_sp); 430 cpp_category_sp->GetTypeSummariesContainer()->Add( 431 ConstString("std::__ndk1::string"), std_string_summary_sp); 432 cpp_category_sp->GetTypeSummariesContainer()->Add( 433 ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, " 434 "std::__1::allocator<char> >"), 435 std_string_summary_sp); 436 cpp_category_sp->GetTypeSummariesContainer()->Add( 437 ConstString( 438 "std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, " 439 "std::__1::allocator<char16_t> >"), 440 std_stringu16_summary_sp); 441 cpp_category_sp->GetTypeSummariesContainer()->Add( 442 ConstString( 443 "std::__1::basic_string<char32_t, std::__1::char_traits<char32_t>, " 444 "std::__1::allocator<char32_t> >"), 445 std_stringu32_summary_sp); 446 cpp_category_sp->GetTypeSummariesContainer()->Add( 447 ConstString("std::__ndk1::basic_string<char, " 448 "std::__ndk1::char_traits<char>, " 449 "std::__ndk1::allocator<char> >"), 450 std_string_summary_sp); 451 452 cpp_category_sp->GetTypeSummariesContainer()->Add( 453 ConstString("std::__1::wstring"), std_wstring_summary_sp); 454 cpp_category_sp->GetTypeSummariesContainer()->Add( 455 ConstString("std::__ndk1::wstring"), std_wstring_summary_sp); 456 cpp_category_sp->GetTypeSummariesContainer()->Add( 457 ConstString("std::__1::basic_string<wchar_t, " 458 "std::__1::char_traits<wchar_t>, " 459 "std::__1::allocator<wchar_t> >"), 460 std_wstring_summary_sp); 461 cpp_category_sp->GetTypeSummariesContainer()->Add( 462 ConstString("std::__ndk1::basic_string<wchar_t, " 463 "std::__ndk1::char_traits<wchar_t>, " 464 "std::__ndk1::allocator<wchar_t> >"), 465 std_wstring_summary_sp); 466 467 SyntheticChildren::Flags stl_synth_flags; 468 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( 469 false); 470 SyntheticChildren::Flags stl_deref_flags = stl_synth_flags; 471 stl_deref_flags.SetFrontEndWantsDereference(); 472 473 AddCXXSynthetic( 474 cpp_category_sp, 475 lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator, 476 "libc++ std::bitset synthetic children", 477 ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"), stl_deref_flags, 478 true); 479 AddCXXSynthetic( 480 cpp_category_sp, 481 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, 482 "libc++ std::vector synthetic children", 483 ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_deref_flags, 484 true); 485 AddCXXSynthetic( 486 cpp_category_sp, 487 lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator, 488 "libc++ std::forward_list synthetic children", 489 ConstString("^std::__(ndk)?1::forward_list<.+>(( )?&)?$"), 490 stl_synth_flags, true); 491 AddCXXSynthetic( 492 cpp_category_sp, 493 lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, 494 "libc++ std::list synthetic children", 495 ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), stl_synth_flags, true); 496 AddCXXSynthetic( 497 cpp_category_sp, 498 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 499 "libc++ std::map synthetic children", 500 ConstString("^std::__(ndk)?1::map<.+> >(( )?&)?$"), stl_synth_flags, 501 true); 502 AddCXXSynthetic( 503 cpp_category_sp, 504 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 505 "libc++ std::set synthetic children", 506 ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_deref_flags, 507 true); 508 AddCXXSynthetic( 509 cpp_category_sp, 510 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 511 "libc++ std::multiset synthetic children", 512 ConstString("^std::__(ndk)?1::multiset<.+> >(( )?&)?$"), stl_deref_flags, 513 true); 514 AddCXXSynthetic( 515 cpp_category_sp, 516 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 517 "libc++ std::multimap synthetic children", 518 ConstString("^std::__(ndk)?1::multimap<.+> >(( )?&)?$"), stl_synth_flags, 519 true); 520 AddCXXSynthetic( 521 cpp_category_sp, 522 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, 523 "libc++ std::unordered containers synthetic children", 524 ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"), 525 stl_synth_flags, true); 526 AddCXXSynthetic( 527 cpp_category_sp, 528 lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, 529 "libc++ std::initializer_list synthetic children", 530 ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, 531 true); 532 AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator, 533 "libc++ std::queue synthetic children", 534 ConstString("^std::__(ndk)?1::queue<.+>(( )?&)?$"), 535 stl_synth_flags, true); 536 AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator, 537 "libc++ std::tuple synthetic children", 538 ConstString("^std::__(ndk)?1::tuple<.*>(( )?&)?$"), stl_synth_flags, 539 true); 540 AddCXXSynthetic(cpp_category_sp, LibcxxOptionalFrontEndCreator, 541 "libc++ std::optional synthetic children", 542 ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), 543 stl_synth_flags, true); 544 AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator, 545 "libc++ std::variant synthetic children", 546 ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"), 547 stl_synth_flags, true); 548 AddCXXSynthetic( 549 cpp_category_sp, 550 lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, 551 "libc++ std::atomic synthetic children", 552 ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_synth_flags, true); 553 554 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 555 RegularExpressionSP(new RegularExpression( 556 llvm::StringRef("^(std::__(ndk)?1::)deque<.+>(( )?&)?$"))), 557 SyntheticChildrenSP(new ScriptedSyntheticChildren( 558 stl_synth_flags, 559 "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); 560 561 AddCXXSynthetic( 562 cpp_category_sp, 563 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, 564 "shared_ptr synthetic children", 565 ConstString("^(std::__(ndk)?1::)shared_ptr<.+>(( )?&)?$"), 566 stl_synth_flags, true); 567 AddCXXSynthetic( 568 cpp_category_sp, 569 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, 570 "weak_ptr synthetic children", 571 ConstString("^(std::__(ndk)?1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, 572 true); 573 574 AddCXXSummary( 575 cpp_category_sp, lldb_private::formatters::LibcxxFunctionSummaryProvider, 576 "libc++ std::function summary provider", 577 ConstString("^std::__(ndk)?1::function<.+>$"), stl_summary_flags, true); 578 579 stl_summary_flags.SetDontShowChildren(false); 580 stl_summary_flags.SetSkipPointers(false); 581 AddCXXSummary(cpp_category_sp, 582 lldb_private::formatters::LibcxxContainerSummaryProvider, 583 "libc++ std::bitset summary provider", 584 ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"), 585 stl_summary_flags, true); 586 AddCXXSummary(cpp_category_sp, 587 lldb_private::formatters::LibcxxContainerSummaryProvider, 588 "libc++ std::vector summary provider", 589 ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), 590 stl_summary_flags, true); 591 AddCXXSummary(cpp_category_sp, 592 lldb_private::formatters::LibcxxContainerSummaryProvider, 593 "libc++ std::list summary provider", 594 ConstString("^std::__(ndk)?1::forward_list<.+>(( )?&)?$"), 595 stl_summary_flags, true); 596 AddCXXSummary(cpp_category_sp, 597 lldb_private::formatters::LibcxxContainerSummaryProvider, 598 "libc++ std::list summary provider", 599 ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), 600 stl_summary_flags, true); 601 AddCXXSummary(cpp_category_sp, 602 lldb_private::formatters::LibcxxContainerSummaryProvider, 603 "libc++ std::map summary provider", 604 ConstString("^std::__(ndk)?1::map<.+>(( )?&)?$"), 605 stl_summary_flags, true); 606 AddCXXSummary(cpp_category_sp, 607 lldb_private::formatters::LibcxxContainerSummaryProvider, 608 "libc++ std::deque summary provider", 609 ConstString("^std::__(ndk)?1::deque<.+>(( )?&)?$"), 610 stl_summary_flags, true); 611 AddCXXSummary(cpp_category_sp, 612 lldb_private::formatters::LibcxxContainerSummaryProvider, 613 "libc++ std::queue summary provider", 614 ConstString("^std::__(ndk)?1::queue<.+>(( )?&)?$"), 615 stl_summary_flags, true); 616 AddCXXSummary(cpp_category_sp, 617 lldb_private::formatters::LibcxxContainerSummaryProvider, 618 "libc++ std::set summary provider", 619 ConstString("^std::__(ndk)?1::set<.+>(( )?&)?$"), 620 stl_summary_flags, true); 621 AddCXXSummary(cpp_category_sp, 622 lldb_private::formatters::LibcxxContainerSummaryProvider, 623 "libc++ std::multiset summary provider", 624 ConstString("^std::__(ndk)?1::multiset<.+>(( )?&)?$"), 625 stl_summary_flags, true); 626 AddCXXSummary(cpp_category_sp, 627 lldb_private::formatters::LibcxxContainerSummaryProvider, 628 "libc++ std::multimap summary provider", 629 ConstString("^std::__(ndk)?1::multimap<.+>(( )?&)?$"), 630 stl_summary_flags, true); 631 AddCXXSummary( 632 cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, 633 "libc++ std::unordered containers summary provider", 634 ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"), 635 stl_summary_flags, true); 636 AddCXXSummary(cpp_category_sp, LibcxxContainerSummaryProvider, 637 "libc++ std::tuple summary provider", 638 ConstString("^std::__(ndk)?1::tuple<.*>(( )?&)?$"), stl_summary_flags, 639 true); 640 AddCXXSummary( 641 cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider, 642 "libc++ std::atomic summary provider", 643 ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_summary_flags, true); 644 AddCXXSummary(cpp_category_sp, 645 lldb_private::formatters::LibcxxOptionalSummaryProvider, 646 "libc++ std::optional summary provider", 647 ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), 648 stl_summary_flags, true); 649 AddCXXSummary(cpp_category_sp, 650 lldb_private::formatters::LibcxxVariantSummaryProvider, 651 "libc++ std::variant summary provider", 652 ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"), 653 stl_summary_flags, true); 654 655 stl_summary_flags.SetSkipPointers(true); 656 657 AddCXXSummary(cpp_category_sp, 658 lldb_private::formatters::LibcxxSmartPointerSummaryProvider, 659 "libc++ std::shared_ptr summary provider", 660 ConstString("^std::__(ndk)?1::shared_ptr<.+>(( )?&)?$"), 661 stl_summary_flags, true); 662 AddCXXSummary(cpp_category_sp, 663 lldb_private::formatters::LibcxxSmartPointerSummaryProvider, 664 "libc++ std::weak_ptr summary provider", 665 ConstString("^std::__(ndk)?1::weak_ptr<.+>(( )?&)?$"), 666 stl_summary_flags, true); 667 668 AddCXXSynthetic( 669 cpp_category_sp, 670 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, 671 "std::vector iterator synthetic children", 672 ConstString("^std::__(ndk)?1::__wrap_iter<.+>$"), stl_synth_flags, true); 673 674 AddCXXSynthetic( 675 cpp_category_sp, 676 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, 677 "std::map iterator synthetic children", 678 ConstString("^std::__(ndk)?1::__map_iterator<.+>$"), stl_synth_flags, 679 true); 680 #endif 681 } 682 683 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 684 if (!cpp_category_sp) 685 return; 686 687 TypeSummaryImpl::Flags stl_summary_flags; 688 stl_summary_flags.SetCascades(true) 689 .SetSkipPointers(false) 690 .SetSkipReferences(false) 691 .SetDontShowChildren(true) 692 .SetDontShowValue(true) 693 .SetShowMembersOneLiner(false) 694 .SetHideItemNames(false); 695 696 lldb::TypeSummaryImplSP std_string_summary_sp( 697 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}")); 698 699 lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat( 700 stl_summary_flags, LibStdcppStringSummaryProvider, 701 "libstdc++ c++11 std::string summary provider")); 702 lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat( 703 stl_summary_flags, LibStdcppWStringSummaryProvider, 704 "libstdc++ c++11 std::wstring summary provider")); 705 706 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"), 707 std_string_summary_sp); 708 cpp_category_sp->GetTypeSummariesContainer()->Add( 709 ConstString("std::basic_string<char>"), std_string_summary_sp); 710 cpp_category_sp->GetTypeSummariesContainer()->Add( 711 ConstString("std::basic_string<char,std::char_traits<char>,std::" 712 "allocator<char> >"), 713 std_string_summary_sp); 714 cpp_category_sp->GetTypeSummariesContainer()->Add( 715 ConstString("std::basic_string<char, std::char_traits<char>, " 716 "std::allocator<char> >"), 717 std_string_summary_sp); 718 719 cpp_category_sp->GetTypeSummariesContainer()->Add( 720 ConstString("std::__cxx11::string"), cxx11_string_summary_sp); 721 cpp_category_sp->GetTypeSummariesContainer()->Add( 722 ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, " 723 "std::allocator<char> >"), 724 cxx11_string_summary_sp); 725 726 // making sure we force-pick the summary for printing wstring (_M_p is a 727 // wchar_t*) 728 lldb::TypeSummaryImplSP std_wstring_summary_sp( 729 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}")); 730 731 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"), 732 std_wstring_summary_sp); 733 cpp_category_sp->GetTypeSummariesContainer()->Add( 734 ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp); 735 cpp_category_sp->GetTypeSummariesContainer()->Add( 736 ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::" 737 "allocator<wchar_t> >"), 738 std_wstring_summary_sp); 739 cpp_category_sp->GetTypeSummariesContainer()->Add( 740 ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, " 741 "std::allocator<wchar_t> >"), 742 std_wstring_summary_sp); 743 744 cpp_category_sp->GetTypeSummariesContainer()->Add( 745 ConstString("std::__cxx11::wstring"), cxx11_wstring_summary_sp); 746 cpp_category_sp->GetTypeSummariesContainer()->Add( 747 ConstString("std::__cxx11::basic_string<wchar_t, " 748 "std::char_traits<wchar_t>, std::allocator<wchar_t> >"), 749 cxx11_wstring_summary_sp); 750 751 #ifndef LLDB_DISABLE_PYTHON 752 753 SyntheticChildren::Flags stl_synth_flags; 754 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( 755 false); 756 757 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 758 RegularExpressionSP( 759 new RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$"))), 760 SyntheticChildrenSP(new ScriptedSyntheticChildren( 761 stl_synth_flags, 762 "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); 763 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 764 RegularExpressionSP( 765 new RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$"))), 766 SyntheticChildrenSP(new ScriptedSyntheticChildren( 767 stl_synth_flags, 768 "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider"))); 769 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 770 RegularExpressionSP(new RegularExpression( 771 llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$"))), 772 SyntheticChildrenSP(new ScriptedSyntheticChildren( 773 stl_synth_flags, 774 "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); 775 stl_summary_flags.SetDontShowChildren(false); 776 stl_summary_flags.SetSkipPointers(true); 777 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 778 RegularExpressionSP( 779 new RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$"))), 780 TypeSummaryImplSP( 781 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 782 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 783 RegularExpressionSP( 784 new RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$"))), 785 TypeSummaryImplSP( 786 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 787 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 788 RegularExpressionSP(new RegularExpression( 789 llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$"))), 790 TypeSummaryImplSP( 791 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 792 793 AddCXXSynthetic( 794 cpp_category_sp, 795 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, 796 "std::vector iterator synthetic children", 797 ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true); 798 799 AddCXXSynthetic( 800 cpp_category_sp, 801 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, 802 "std::map iterator synthetic children", 803 ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true); 804 805 AddCXXSynthetic( 806 cpp_category_sp, 807 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator, 808 "std::unique_ptr synthetic children", 809 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 810 AddCXXSynthetic( 811 cpp_category_sp, 812 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, 813 "std::shared_ptr synthetic children", 814 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 815 AddCXXSynthetic( 816 cpp_category_sp, 817 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, 818 "std::weak_ptr synthetic children", 819 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 820 AddCXXSynthetic( 821 cpp_category_sp, 822 lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator, 823 "std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"), 824 stl_synth_flags, true); 825 826 AddCXXSummary(cpp_category_sp, 827 lldb_private::formatters::LibStdcppUniquePointerSummaryProvider, 828 "libstdc++ std::unique_ptr summary provider", 829 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_summary_flags, 830 true); 831 AddCXXSummary(cpp_category_sp, 832 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, 833 "libstdc++ std::shared_ptr summary provider", 834 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, 835 true); 836 AddCXXSummary(cpp_category_sp, 837 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, 838 "libstdc++ std::weak_ptr summary provider", 839 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, 840 true); 841 #endif 842 } 843 844 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 845 if (!cpp_category_sp) 846 return; 847 848 TypeSummaryImpl::Flags string_flags; 849 string_flags.SetCascades(true) 850 .SetSkipPointers(true) 851 .SetSkipReferences(false) 852 .SetDontShowChildren(true) 853 .SetDontShowValue(false) 854 .SetShowMembersOneLiner(false) 855 .SetHideItemNames(false); 856 857 TypeSummaryImpl::Flags string_array_flags; 858 string_array_flags.SetCascades(true) 859 .SetSkipPointers(true) 860 .SetSkipReferences(false) 861 .SetDontShowChildren(true) 862 .SetDontShowValue(true) 863 .SetShowMembersOneLiner(false) 864 .SetHideItemNames(false); 865 866 #ifndef LLDB_DISABLE_PYTHON 867 // FIXME because of a bug in the FormattersContainer we need to add a summary 868 // for both X* and const X* (<rdar://problem/12717717>) 869 AddCXXSummary( 870 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, 871 "char16_t * summary provider", ConstString("char16_t *"), string_flags); 872 AddCXXSummary(cpp_category_sp, 873 lldb_private::formatters::Char16StringSummaryProvider, 874 "char16_t [] summary provider", 875 ConstString("char16_t \\[[0-9]+\\]"), string_array_flags, true); 876 877 AddCXXSummary( 878 cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider, 879 "char32_t * summary provider", ConstString("char32_t *"), string_flags); 880 AddCXXSummary(cpp_category_sp, 881 lldb_private::formatters::Char32StringSummaryProvider, 882 "char32_t [] summary provider", 883 ConstString("char32_t \\[[0-9]+\\]"), string_array_flags, true); 884 885 AddCXXSummary( 886 cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, 887 "wchar_t * summary provider", ConstString("wchar_t *"), string_flags); 888 AddCXXSummary(cpp_category_sp, 889 lldb_private::formatters::WCharStringSummaryProvider, 890 "wchar_t * summary provider", 891 ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true); 892 893 AddCXXSummary( 894 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, 895 "unichar * summary provider", ConstString("unichar *"), string_flags); 896 897 TypeSummaryImpl::Flags widechar_flags; 898 widechar_flags.SetDontShowValue(true) 899 .SetSkipPointers(true) 900 .SetSkipReferences(false) 901 .SetCascades(true) 902 .SetDontShowChildren(true) 903 .SetHideItemNames(true) 904 .SetShowMembersOneLiner(false); 905 906 AddCXXSummary( 907 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, 908 "char16_t summary provider", ConstString("char16_t"), widechar_flags); 909 AddCXXSummary( 910 cpp_category_sp, lldb_private::formatters::Char32SummaryProvider, 911 "char32_t summary provider", ConstString("char32_t"), widechar_flags); 912 AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider, 913 "wchar_t summary provider", ConstString("wchar_t"), 914 widechar_flags); 915 916 AddCXXSummary( 917 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, 918 "unichar summary provider", ConstString("unichar"), widechar_flags); 919 #endif 920 } 921 922 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() { 923 class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger { 924 public: 925 virtual CompilerType AdjustForInclusion(CompilerType &candidate) override { 926 LanguageType lang_type(candidate.GetMinimumLanguage()); 927 if (!Language::LanguageIsC(lang_type) && 928 !Language::LanguageIsCPlusPlus(lang_type)) 929 return CompilerType(); 930 if (candidate.IsTypedefType()) 931 return candidate.GetTypedefedType(); 932 return candidate; 933 } 934 }; 935 936 return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger()); 937 } 938 939 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() { 940 static llvm::once_flag g_initialize; 941 static TypeCategoryImplSP g_category; 942 943 llvm::call_once(g_initialize, [this]() -> void { 944 DataVisualization::Categories::GetCategory(GetPluginName(), g_category); 945 if (g_category) { 946 LoadLibCxxFormatters(g_category); 947 LoadLibStdcppFormatters(g_category); 948 LoadSystemFormatters(g_category); 949 } 950 }); 951 return g_category; 952 } 953 954 HardcodedFormatters::HardcodedSummaryFinder 955 CPlusPlusLanguage::GetHardcodedSummaries() { 956 static llvm::once_flag g_initialize; 957 static ConstString g_vectortypes("VectorTypes"); 958 static HardcodedFormatters::HardcodedSummaryFinder g_formatters; 959 960 llvm::call_once(g_initialize, []() -> void { 961 g_formatters.push_back( 962 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 963 FormatManager &) -> TypeSummaryImpl::SharedPointer { 964 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 965 new CXXFunctionSummaryFormat( 966 TypeSummaryImpl::Flags(), 967 lldb_private::formatters::CXXFunctionPointerSummaryProvider, 968 "Function pointer summary provider")); 969 if (valobj.GetCompilerType().IsFunctionPointerType()) { 970 return formatter_sp; 971 } 972 return nullptr; 973 }); 974 g_formatters.push_back( 975 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 976 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer { 977 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 978 new CXXFunctionSummaryFormat( 979 TypeSummaryImpl::Flags() 980 .SetCascades(true) 981 .SetDontShowChildren(true) 982 .SetHideItemNames(true) 983 .SetShowMembersOneLiner(true) 984 .SetSkipPointers(true) 985 .SetSkipReferences(false), 986 lldb_private::formatters::VectorTypeSummaryProvider, 987 "vector_type pointer summary provider")); 988 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { 989 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) 990 return formatter_sp; 991 } 992 return nullptr; 993 }); 994 g_formatters.push_back( 995 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 996 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer { 997 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 998 new CXXFunctionSummaryFormat( 999 TypeSummaryImpl::Flags() 1000 .SetCascades(true) 1001 .SetDontShowChildren(true) 1002 .SetHideItemNames(true) 1003 .SetShowMembersOneLiner(true) 1004 .SetSkipPointers(true) 1005 .SetSkipReferences(false), 1006 lldb_private::formatters::BlockPointerSummaryProvider, 1007 "block pointer summary provider")); 1008 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { 1009 return formatter_sp; 1010 } 1011 return nullptr; 1012 }); 1013 }); 1014 1015 return g_formatters; 1016 } 1017 1018 HardcodedFormatters::HardcodedSyntheticFinder 1019 CPlusPlusLanguage::GetHardcodedSynthetics() { 1020 static llvm::once_flag g_initialize; 1021 static ConstString g_vectortypes("VectorTypes"); 1022 static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; 1023 1024 llvm::call_once(g_initialize, []() -> void { 1025 g_formatters.push_back([](lldb_private::ValueObject &valobj, 1026 lldb::DynamicValueType, 1027 FormatManager & 1028 fmt_mgr) -> SyntheticChildren::SharedPointer { 1029 static CXXSyntheticChildren::SharedPointer formatter_sp( 1030 new CXXSyntheticChildren( 1031 SyntheticChildren::Flags() 1032 .SetCascades(true) 1033 .SetSkipPointers(true) 1034 .SetSkipReferences(true) 1035 .SetNonCacheable(true), 1036 "vector_type synthetic children", 1037 lldb_private::formatters::VectorTypeSyntheticFrontEndCreator)); 1038 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { 1039 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) 1040 return formatter_sp; 1041 } 1042 return nullptr; 1043 }); 1044 g_formatters.push_back([](lldb_private::ValueObject &valobj, 1045 lldb::DynamicValueType, 1046 FormatManager & 1047 fmt_mgr) -> SyntheticChildren::SharedPointer { 1048 static CXXSyntheticChildren::SharedPointer formatter_sp( 1049 new CXXSyntheticChildren( 1050 SyntheticChildren::Flags() 1051 .SetCascades(true) 1052 .SetSkipPointers(true) 1053 .SetSkipReferences(true) 1054 .SetNonCacheable(true), 1055 "block pointer synthetic children", 1056 lldb_private::formatters::BlockPointerSyntheticFrontEndCreator)); 1057 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { 1058 return formatter_sp; 1059 } 1060 return nullptr; 1061 }); 1062 1063 }); 1064 1065 return g_formatters; 1066 } 1067 1068 bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { 1069 const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c", 1070 ".h", ".hh", ".hpp", ".hxx", ".h++"}; 1071 for (auto suffix : suffixes) { 1072 if (file_path.endswith_lower(suffix)) 1073 return true; 1074 } 1075 1076 // Check if we're in a STL path (where the files usually have no extension 1077 // that we could check for. 1078 return file_path.contains("/usr/include/c++/"); 1079 } 1080