1193323Sed//===-- TypeMap.cpp -------------------------------------------------------===// 2193323Sed// 3193323Sed// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4193323Sed// See https://llvm.org/LICENSE.txt for license information. 5193323Sed// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6193323Sed// 7193323Sed//===----------------------------------------------------------------------===// 8193323Sed 9193323Sed#include <vector> 10193323Sed 11193323Sed#include "llvm/Support/FormattedStream.h" 12193323Sed#include "llvm/Support/raw_ostream.h" 13193323Sed 14193323Sed#include "lldb/Symbol/SymbolFile.h" 15193323Sed#include "lldb/Symbol/SymbolVendor.h" 16193323Sed#include "lldb/Symbol/Type.h" 17193323Sed#include "lldb/Symbol/TypeMap.h" 18193323Sed 19193323Sedusing namespace lldb; 20193323Sedusing namespace lldb_private; 21193323Sed 22193323SedTypeMap::TypeMap() : m_types() {} 23193323Sed 24203954Srdivacky// Destructor 25203954SrdivackyTypeMap::~TypeMap() = default; 26203954Srdivacky 27198090Srdivackyvoid TypeMap::Insert(const TypeSP &type_sp) { 28193323Sed // Just push each type on the back for now. We will worry about uniquing 29193323Sed // later 30193323Sed if (type_sp) 31193323Sed m_types.insert(std::make_pair(type_sp->GetID(), type_sp)); 32198090Srdivacky} 33193323Sed 34193323Sedbool TypeMap::InsertUnique(const TypeSP &type_sp) { 35193323Sed if (type_sp) { 36193323Sed user_id_t type_uid = type_sp->GetID(); 37193323Sed iterator pos, end = m_types.end(); 38193323Sed 39193323Sed for (pos = m_types.find(type_uid); 40193323Sed pos != end && pos->second->GetID() == type_uid; ++pos) { 41193323Sed if (pos->second.get() == type_sp.get()) 42193323Sed return false; 43193323Sed } 44193323Sed Insert(type_sp); 45193323Sed } 46193323Sed return true; 47193323Sed} 48193323Sed 49193323Sed// Find a base type by its unique ID. 50193323Sed// TypeSP 51193323Sed// TypeMap::FindType(lldb::user_id_t uid) 52193323Sed//{ 53193323Sed// iterator pos = m_types.find(uid); 54193323Sed// if (pos != m_types.end()) 55193323Sed// return pos->second; 56193323Sed// return TypeSP(); 57193323Sed//} 58193323Sed 59193323Sed// Find a type by name. 60193323Sed// TypeMap 61193323Sed// TypeMap::FindTypes (ConstString name) 62193323Sed//{ 63193323Sed// // Do we ever need to make a lookup by name map? Here we are doing 64193323Sed// // a linear search which isn't going to be fast. 65193323Sed// TypeMap types(m_ast.getTargetInfo()->getTriple().getTriple().c_str()); 66193323Sed// iterator pos, end; 67193323Sed// for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) 68193323Sed// if (pos->second->GetName() == name) 69193323Sed// types.Insert (pos->second); 70193323Sed// return types; 71193323Sed//} 72193323Sed 73193323Sedvoid TypeMap::Clear() { m_types.clear(); } 74193323Sed 75193323Seduint32_t TypeMap::GetSize() const { return m_types.size(); } 76193323Sed 77193323Sedbool TypeMap::Empty() const { return m_types.empty(); } 78193323Sed 79193323Sed// GetTypeAtIndex isn't used a lot for large type lists, currently only for 80193323Sed// type lists that are returned for "image dump -t TYPENAME" commands and other 81193323Sed// simple symbol queries that grab the first result... 82198892Srdivacky 83198892SrdivackyTypeSP TypeMap::GetTypeAtIndex(uint32_t idx) { 84198892Srdivacky iterator pos, end; 85198892Srdivacky uint32_t i = idx; 86193323Sed for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) { 87193323Sed if (i == 0) 88193323Sed return pos->second; 89193323Sed --i; 90193323Sed } 91193323Sed return TypeSP(); 92193323Sed} 93193323Sed 94193323Sedlldb::TypeSP TypeMap::FirstType() const { 95193323Sed if (m_types.empty()) 96193323Sed return TypeSP(); 97193323Sed return m_types.begin()->second; 98199989Srdivacky} 99199989Srdivacky 100193323Sedvoid TypeMap::ForEach( 101193323Sed std::function<bool(const lldb::TypeSP &type_sp)> const &callback) const { 102193323Sed for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) { 103199989Srdivacky if (!callback(pos->second)) 104199989Srdivacky break; 105199989Srdivacky } 106199989Srdivacky} 107198892Srdivacky 108198892Srdivackyvoid TypeMap::ForEach( 109198892Srdivacky std::function<bool(lldb::TypeSP &type_sp)> const &callback) { 110198892Srdivacky for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) { 111198892Srdivacky if (!callback(pos->second)) 112198892Srdivacky break; 113198892Srdivacky } 114198892Srdivacky} 115193323Sed 116193323Sedbool TypeMap::Remove(const lldb::TypeSP &type_sp) { 117193323Sed if (type_sp) { 118193323Sed lldb::user_id_t uid = type_sp->GetID(); 119193323Sed for (iterator pos = m_types.find(uid), end = m_types.end(); 120193323Sed pos != end && pos->first == uid; ++pos) { 121193323Sed if (pos->second == type_sp) { 122193323Sed m_types.erase(pos); 123193323Sed return true; 124193323Sed } 125193323Sed } 126193323Sed } 127193323Sed return false; 128193323Sed} 129193323Sed 130193323Sedvoid TypeMap::Dump(Stream *s, bool show_context, 131193323Sed lldb::DescriptionLevel level) const { 132193323Sed for (const auto &pair : m_types) 133193323Sed pair.second->Dump(s, show_context, level); 134193323Sed} 135193323Sed 136193323Sedvoid TypeMap::RemoveMismatchedTypes(llvm::StringRef type_scope, 137193323Sed llvm::StringRef type_basename, 138193323Sed TypeClass type_class, bool exact_match) { 139193323Sed // Our "collection" type currently is a std::map which doesn't have any good 140193323Sed // way to iterate and remove items from the map so we currently just make a 141193323Sed // new list and add all of the matching types to it, and then swap it into 142193323Sed // m_types at the end 143193323Sed collection matching_types; 144193323Sed 145193323Sed iterator pos, end = m_types.end(); 146193323Sed 147193323Sed for (pos = m_types.begin(); pos != end; ++pos) { 148193323Sed Type *the_type = pos->second.get(); 149193323Sed bool keep_match = false; 150193323Sed TypeClass match_type_class = eTypeClassAny; 151193323Sed 152193323Sed if (type_class != eTypeClassAny) { 153193323Sed match_type_class = the_type->GetForwardCompilerType().GetTypeClass(); 154193323Sed if ((match_type_class & type_class) == 0) 155193323Sed continue; 156193323Sed } 157193323Sed 158193323Sed ConstString match_type_name_const_str(the_type->GetQualifiedName()); 159193323Sed if (match_type_name_const_str) { 160193323Sed const char *match_type_name = match_type_name_const_str.GetCString(); 161193323Sed llvm::StringRef match_type_scope; 162193323Sed llvm::StringRef match_type_basename; 163193323Sed if (Type::GetTypeScopeAndBasename(match_type_name, match_type_scope, 164193323Sed match_type_basename, 165193323Sed match_type_class)) { 166193323Sed if (match_type_basename == type_basename) { 167193323Sed const size_t type_scope_size = type_scope.size(); 168193323Sed const size_t match_type_scope_size = match_type_scope.size(); 169193323Sed if (exact_match || (type_scope_size == match_type_scope_size)) { 170193323Sed keep_match = match_type_scope == type_scope; 171193323Sed } else { 172193323Sed if (match_type_scope_size > type_scope_size) { 173193323Sed const size_t type_scope_pos = match_type_scope.rfind(type_scope); 174193323Sed if (type_scope_pos == match_type_scope_size - type_scope_size) { 175193323Sed if (type_scope_pos >= 2) { 176193323Sed // Our match scope ends with the type scope we were looking 177193323Sed // for, but we need to make sure what comes before the 178193323Sed // matching type scope is a namespace boundary in case we are 179193323Sed // trying to match: type_basename = "d" type_scope = "b::c::" 180193323Sed // We want to match: 181193323Sed // match_type_scope "a::b::c::" 182193323Sed // But not: 183193323Sed // match_type_scope "a::bb::c::" 184193323Sed // So below we make sure what comes before "b::c::" in 185193323Sed // match_type_scope is "::", or the namespace boundary 186193323Sed if (match_type_scope[type_scope_pos - 1] == ':' && 187193323Sed match_type_scope[type_scope_pos - 2] == ':') { 188193323Sed keep_match = true; 189193323Sed } 190193323Sed } 191193323Sed } 192193323Sed } 193193323Sed } 194193323Sed } 195193323Sed } else { 196193323Sed // The type we are currently looking at doesn't exists in a namespace 197193323Sed // or class, so it only matches if there is no type scope... 198193323Sed keep_match = type_scope.empty() && type_basename == match_type_name; 199193323Sed } 200193323Sed } 201193323Sed 202193323Sed if (keep_match) { 203193323Sed matching_types.insert(*pos); 204193323Sed } 205193323Sed } 206193323Sed m_types.swap(matching_types); 207193323Sed} 208193323Sed