|
16 | 16 | #include "lldb/Interpreter/OptionValueProperties.h" |
17 | 17 | #include "lldb/Symbol/SymbolFile.h" |
18 | 18 | #include "lldb/Symbol/TypeList.h" |
| 19 | +#include "lldb/Symbol/VariableList.h" |
19 | 20 | #include "lldb/Target/Target.h" |
20 | 21 | #include "lldb/Utility/Stream.h" |
21 | 22 |
|
| 23 | +#include "llvm/ADT/MapVector.h" |
22 | 24 | #include "llvm/BinaryFormat/Dwarf.h" |
23 | 25 | #include "llvm/Support/Threading.h" |
24 | 26 |
|
@@ -574,3 +576,76 @@ bool SourceLanguage::IsObjC() const { |
574 | 576 | bool SourceLanguage::IsCPlusPlus() const { |
575 | 577 | return name == llvm::dwarf::DW_LNAME_C_plus_plus; |
576 | 578 | } |
| 579 | + |
| 580 | +// BEGIN SWIFT |
| 581 | +// Implement LanguageCPlusPlus::GetParentNameIfClosure and upstream this. |
| 582 | +// rdar://152321823 |
| 583 | + |
| 584 | +/// If `sc` represents a "closure"-like function (according to |
| 585 | +/// Language::GetParentNameIfClosure), returns all parent functions up to and |
| 586 | +/// including the first non-closure-like function. If `sc` is not a closure, or |
| 587 | +/// if the query does not make sense for `language`, returns an empty list. |
| 588 | +static llvm::SmallVector<Function *> |
| 589 | +GetParentFunctionsWhileClosure(const SymbolContext &sc, |
| 590 | + const Language &language) { |
| 591 | + // The algorithm below terminates on the assumption that |
| 592 | + // `GetParentNameIfClosure` produces an empty string when composing that |
| 593 | + // function with itself enough times. For safety, define an upper limit. |
| 594 | + constexpr auto upper_limit = 8; |
| 595 | + |
| 596 | + llvm::SmallVector<Function *> parents; |
| 597 | + Function *root = sc.function; |
| 598 | + if (root == nullptr) |
| 599 | + return parents; |
| 600 | + |
| 601 | + for (int idx = 0; idx < upper_limit; idx++) { |
| 602 | + ConstString mangled = root->GetMangled().GetMangledName(); |
| 603 | + std::string parent = language.GetParentNameIfClosure(mangled); |
| 604 | + if (parent.empty()) |
| 605 | + break; |
| 606 | + |
| 607 | + // Find the enclosing function, if it exists. |
| 608 | + SymbolContextList sc_list; |
| 609 | + Module::LookupInfo lookup_info( |
| 610 | + ConstString(parent), lldb::FunctionNameType::eFunctionNameTypeFull, |
| 611 | + lldb::eLanguageTypeSwift); |
| 612 | + sc.module_sp->FindFunctions(lookup_info, CompilerDeclContext(), |
| 613 | + ModuleFunctionSearchOptions(), sc_list); |
| 614 | + if (sc_list.GetSize() != 1 || sc_list[0].function == nullptr) |
| 615 | + break; |
| 616 | + parents.push_back(sc_list[0].function); |
| 617 | + root = sc_list[0].function; |
| 618 | + } |
| 619 | + return parents; |
| 620 | +} |
| 621 | + |
| 622 | +/// Given a list of functions, returns a map: Function -> VariableList |
| 623 | +/// containing local variables of each function. |
| 624 | +static llvm::MapVector<Function *, VariableList> |
| 625 | +GetFuncToLocalVariablesMap(llvm::ArrayRef<Function *> funcs) { |
| 626 | + llvm::MapVector<Function *, VariableList> map; |
| 627 | + for (Function *function : funcs) { |
| 628 | + VariableList &variable_list = map[function]; |
| 629 | + Block &block = function->GetBlock(true /*can_create=*/); |
| 630 | + block.AppendBlockVariables( |
| 631 | + true /*can_create=*/, true /*get_child_block_variables=*/, |
| 632 | + true /*stop_if_child_block_is_inlined_function=*/, |
| 633 | + [](Variable *v) { return true; }, &variable_list); |
| 634 | + } |
| 635 | + return map; |
| 636 | +} |
| 637 | + |
| 638 | +Function *Language::FindParentOfClosureWithVariable( |
| 639 | + llvm::StringRef variable_name, const SymbolContext &closure_sc) const { |
| 640 | + llvm::SmallVector<Function *> parent_funcs = |
| 641 | + GetParentFunctionsWhileClosure(closure_sc, *this); |
| 642 | + llvm::MapVector<Function *, VariableList> func_to_locals = |
| 643 | + GetFuncToLocalVariablesMap(parent_funcs); |
| 644 | + |
| 645 | + for (const auto &[func, locals] : func_to_locals) |
| 646 | + for (const VariableSP &var_sp : locals) |
| 647 | + if (var_sp->GetName() == variable_name) |
| 648 | + return func; |
| 649 | + return nullptr; |
| 650 | +} |
| 651 | +// END SWIFT |
0 commit comments