1 //===-- DWARFDeclContext.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 "DWARFDeclContext.h" 10 #include "llvm/Support/raw_ostream.h" 11 12 using namespace lldb_private::dwarf; 13 using namespace lldb_private::plugin::dwarf; 14 15 /// Returns the name of `entry` if it has one, or the appropriate "anonymous 16 /// {namespace, class, struct, union}". 17 static const char *GetName(DWARFDeclContext::Entry entry) { 18 if (entry.name != nullptr) 19 return entry.name; 20 if (entry.tag == DW_TAG_namespace) 21 return "(anonymous namespace)"; 22 if (entry.tag == DW_TAG_class_type) 23 return "(anonymous class)"; 24 if (entry.tag == DW_TAG_structure_type) 25 return "(anonymous struct)"; 26 if (entry.tag == DW_TAG_union_type) 27 return "(anonymous union)"; 28 return "(anonymous)"; 29 } 30 31 const char *DWARFDeclContext::GetQualifiedName() const { 32 if (m_qualified_name.empty()) { 33 // The declaration context array for a class named "foo" in namespace 34 // "a::b::c" will be something like: 35 // [0] DW_TAG_class_type "foo" 36 // [1] DW_TAG_namespace "c" 37 // [2] DW_TAG_namespace "b" 38 // [3] DW_TAG_namespace "a" 39 if (!m_entries.empty()) { 40 if (m_entries.size() == 1) { 41 if (m_entries[0].name) { 42 m_qualified_name.append("::"); 43 m_qualified_name.append(m_entries[0].name); 44 } 45 } else { 46 llvm::raw_string_ostream string_stream(m_qualified_name); 47 llvm::interleave( 48 llvm::reverse(m_entries), string_stream, 49 [&](auto entry) { string_stream << GetName(entry); }, "::"); 50 } 51 } 52 } 53 if (m_qualified_name.empty()) 54 return nullptr; 55 return m_qualified_name.c_str(); 56 } 57 58 bool DWARFDeclContext::operator==(const DWARFDeclContext &rhs) const { 59 if (m_entries.size() != rhs.m_entries.size()) 60 return false; 61 62 collection::const_iterator pos; 63 collection::const_iterator begin = m_entries.begin(); 64 collection::const_iterator end = m_entries.end(); 65 66 collection::const_iterator rhs_pos; 67 collection::const_iterator rhs_begin = rhs.m_entries.begin(); 68 // The two entry arrays have the same size 69 70 // First compare the tags before we do expensive name compares 71 for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) { 72 if (pos->tag != rhs_pos->tag) { 73 // Check for DW_TAG_structure_type and DW_TAG_class_type as they are 74 // often used interchangeably in GCC 75 if (pos->tag == DW_TAG_structure_type && 76 rhs_pos->tag == DW_TAG_class_type) 77 continue; 78 if (pos->tag == DW_TAG_class_type && 79 rhs_pos->tag == DW_TAG_structure_type) 80 continue; 81 return false; 82 } 83 } 84 // The tags all match, now compare the names 85 for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) { 86 if (!pos->NameMatches(*rhs_pos)) 87 return false; 88 } 89 // All tags and names match 90 return true; 91 } 92