Index: lit/SymbolFile/DWARF/find-method-local-struct.cpp =================================================================== --- lit/SymbolFile/DWARF/find-method-local-struct.cpp +++ lit/SymbolFile/DWARF/find-method-local-struct.cpp @@ -1,6 +1,3 @@ -// llvm.org/pr37537 -// XFAIL: * - // RUN: clang %s -g -c -o %t --target=x86_64-apple-macosx // RUN: lldb-test symbols --name=foo --find=function --function-flags=method %t | \ // RUN: FileCheck %s Index: source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -146,6 +146,14 @@ m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets); } +static bool KeepFunctionDIE(DWARFDIE die, uint32_t name_type_mask) { + bool looking_for_methods = name_type_mask & eFunctionNameTypeMethod; + bool looking_for_functions = name_type_mask & eFunctionNameTypeBase; + if (looking_for_methods && looking_for_functions) + return true; + return looking_for_methods == die.IsMethod(); +} + void AppleDWARFIndex::GetFunctions( ConstString name, DWARFDebugInfo &info, llvm::function_refGetType(); - - if (type) { - CompilerDeclContext decl_ctx = - get_decl_context_containing_uid(type->GetID()); - if (decl_ctx.IsStructUnionOrClass()) { - if (name_type_mask & eFunctionNameTypeBase) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } else { - if (name_type_mask & eFunctionNameTypeMethod) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } - } else { - m_module.ReportWarning( - "function at die offset 0x%8.8x had no function type", - die_ref.die_offset); - } - } - } - } - if (keep_die) - resolved_dies.insert(die.GetDIE()); - } + if (resolve_function(die, include_inlines, sc_list)) + resolved_dies.insert(die.GetDIE()); } else ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); } Index: source/Plugins/SymbolFile/DWARF/DWARFDIE.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -11,15 +11,20 @@ #define SymbolFileDWARF_DWARFDIE_h_ #include "DWARFBaseDIE.h" +#include "llvm/ADT/SmallSet.h" class DWARFDIE : public DWARFBaseDIE { public: + class ElaboratingDIEIterator; + using DWARFBaseDIE::DWARFBaseDIE; //---------------------------------------------------------------------- // Tests //---------------------------------------------------------------------- - bool IsStructClassOrUnion() const; + bool IsStructUnionOrClass() const; + + bool IsMethod() const; //---------------------------------------------------------------------- // Accessors @@ -29,6 +34,8 @@ DWARFDIE GetContainingDWOModuleDIE() const; + inline llvm::iterator_range elaborating_dies() const; + //---------------------------------------------------------------------- // Accessing information about a DIE //---------------------------------------------------------------------- @@ -112,4 +119,58 @@ lldb_private::CompilerDeclContext GetContainingDeclContext() const; }; +/// Iterate through all DIEs elaborating (i.e. reachable by a chain of +/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For +/// convenience, the starting die is included in the sequence as the first +/// item. +class DWARFDIE::ElaboratingDIEIterator + : public std::iterator { + + // The operating invariant is: top of m_worklist contains the "current" item + // and the rest of the list are items yet to be visited. An empty worklist + // means we've reached the end. + // Infinite recursion is prevented by maintaining a list of seen DIEs. + // Container sizes are optimized for the case of following DW_AT_specification + // and DW_AT_abstract_origin just once. + llvm::SmallVector m_worklist; + llvm::SmallSet m_seen; + + void Next(); + +public: + /// An iterator starting at die d. + explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} + + /// End marker + ElaboratingDIEIterator() {} + + const DWARFDIE &operator*() const { return m_worklist.back(); } + ElaboratingDIEIterator &operator++() { + Next(); + return *this; + } + ElaboratingDIEIterator operator++(int) { + ElaboratingDIEIterator I = *this; + Next(); + return I; + } + + friend bool operator==(const ElaboratingDIEIterator &a, + const ElaboratingDIEIterator &b) { + if (a.m_worklist.empty() || b.m_worklist.empty()) + return a.m_worklist.empty() == b.m_worklist.empty(); + return a.m_worklist.back() == b.m_worklist.back(); + } + friend bool operator!=(const ElaboratingDIEIterator &a, + const ElaboratingDIEIterator &b) { + return !(a == b); + } +}; + +llvm::iterator_range +DWARFDIE::elaborating_dies() const { + return llvm::make_range(ElaboratingDIEIterator(*this), + ElaboratingDIEIterator()); +} + #endif // SymbolFileDWARF_DWARFDIE_h_ Index: source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -10,15 +10,29 @@ #include "DWARFDIE.h" #include "DWARFASTParser.h" -#include "DWARFUnit.h" #include "DWARFDIECollection.h" #include "DWARFDebugInfo.h" -#include "DWARFDeclContext.h" - #include "DWARFDebugInfoEntry.h" +#include "DWARFDeclContext.h" +#include "DWARFUnit.h" using namespace lldb_private; +void DWARFDIE::ElaboratingDIEIterator::Next() { + assert(!m_worklist.empty() && "Incrementing end iterator?"); + + // Pop the current item from the list. + DWARFDIE die = m_worklist.back(); + m_worklist.pop_back(); + + // And add back any items that elaborate it. + for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) { + if (DWARFDIE d = die.GetReferencedDIE(attr)) + if (m_seen.insert(die.GetID()).second) + m_worklist.push_back(d); + } +} + DWARFDIE DWARFDIE::GetParent() const { if (IsValid()) @@ -209,12 +223,19 @@ return DWARFDIE(); } -bool DWARFDIE::IsStructClassOrUnion() const { +bool DWARFDIE::IsStructUnionOrClass() const { const dw_tag_t tag = Tag(); return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || tag == DW_TAG_union_type; } +bool DWARFDIE::IsMethod() const { + for (DWARFDIE d: elaborating_dies()) + if (d.GetParent().IsStructUnionOrClass()) + return true; + return false; +} + DWARFDIE DWARFDIE::GetContainingDWOModuleDIE() const { if (IsValid()) { Index: source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -288,22 +288,7 @@ } // If we have a mangled name, then the DW_AT_name attribute is // usually the method name without the class or any parameters - const DWARFDebugInfoEntry *parent = die.GetParent(); - bool is_method = false; - if (parent) { - DWARFDIE parent_die(&unit, parent); - if (parent_die.IsStructClassOrUnion()) - is_method = true; - else { - if (specification_die_form.IsValid()) { - DWARFDIE specification_die = - unit.GetSymbolFileDWARF()->DebugInfo()->GetDIE( - DIERef(specification_die_form)); - if (specification_die.GetParent().IsStructClassOrUnion()) - is_method = true; - } - } - } + bool is_method = DWARFDIE(&unit, &die).IsMethod(); if (is_method) set.function_methods.Insert(ConstString(name),