1254721Semaste//===-- TypeList.cpp --------------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#include <vector>
10254721Semaste
11254721Semaste#include "llvm/Support/FormattedStream.h"
12254721Semaste#include "llvm/Support/raw_ostream.h"
13254721Semaste
14254721Semaste#include "lldb/Symbol/SymbolFile.h"
15254721Semaste#include "lldb/Symbol/SymbolVendor.h"
16254721Semaste#include "lldb/Symbol/Type.h"
17254721Semaste#include "lldb/Symbol/TypeList.h"
18254721Semaste
19254721Semasteusing namespace lldb;
20254721Semasteusing namespace lldb_private;
21254721Semaste
22314564SdimTypeList::TypeList() : m_types() {}
23254721Semaste
24254721Semaste// Destructor
25314564SdimTypeList::~TypeList() {}
26254721Semaste
27314564Sdimvoid TypeList::Insert(const TypeSP &type_sp) {
28341825Sdim  // Just push each type on the back for now. We will worry about uniquing
29341825Sdim  // later
30314564Sdim  if (type_sp)
31314564Sdim    m_types.push_back(type_sp);
32254721Semaste}
33254721Semaste
34254721Semaste// Find a base type by its unique ID.
35314564Sdim// TypeSP
36314564Sdim// TypeList::FindType(lldb::user_id_t uid)
37254721Semaste//{
38254721Semaste//    iterator pos = m_types.find(uid);
39254721Semaste//    if (pos != m_types.end())
40254721Semaste//        return pos->second;
41254721Semaste//    return TypeSP();
42254721Semaste//}
43254721Semaste
44254721Semaste// Find a type by name.
45314564Sdim// TypeList
46353358Sdim// TypeList::FindTypes (ConstString name)
47254721Semaste//{
48254721Semaste//    // Do we ever need to make a lookup by name map? Here we are doing
49254721Semaste//    // a linear search which isn't going to be fast.
50254721Semaste//    TypeList types(m_ast.getTargetInfo()->getTriple().getTriple().c_str());
51254721Semaste//    iterator pos, end;
52254721Semaste//    for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
53254721Semaste//        if (pos->second->GetName() == name)
54254721Semaste//            types.Insert (pos->second);
55254721Semaste//    return types;
56254721Semaste//}
57254721Semaste
58314564Sdimvoid TypeList::Clear() { m_types.clear(); }
59254721Semaste
60314564Sdimuint32_t TypeList::GetSize() const { return m_types.size(); }
61254721Semaste
62254721Semaste// GetTypeAtIndex isn't used a lot for large type lists, currently only for
63254721Semaste// type lists that are returned for "image dump -t TYPENAME" commands and other
64254721Semaste// simple symbol queries that grab the first result...
65254721Semaste
66314564SdimTypeSP TypeList::GetTypeAtIndex(uint32_t idx) {
67314564Sdim  iterator pos, end;
68314564Sdim  uint32_t i = idx;
69341825Sdim  assert(i < GetSize() && "Accessing past the end of a TypeList");
70314564Sdim  for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) {
71314564Sdim    if (i == 0)
72314564Sdim      return *pos;
73314564Sdim    --i;
74314564Sdim  }
75314564Sdim  return TypeSP();
76254721Semaste}
77254721Semaste
78314564Sdimvoid TypeList::ForEach(
79314564Sdim    std::function<bool(const lldb::TypeSP &type_sp)> const &callback) const {
80314564Sdim  for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) {
81314564Sdim    if (!callback(*pos))
82314564Sdim      break;
83314564Sdim  }
84254721Semaste}
85254721Semaste
86314564Sdimvoid TypeList::ForEach(
87314564Sdim    std::function<bool(lldb::TypeSP &type_sp)> const &callback) {
88314564Sdim  for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) {
89314564Sdim    if (!callback(*pos))
90314564Sdim      break;
91314564Sdim  }
92254721Semaste}
93254721Semaste
94314564Sdimvoid TypeList::Dump(Stream *s, bool show_context) {
95314564Sdim  for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) {
96314564Sdim    pos->get()->Dump(s, show_context);
97314564Sdim  }
98254721Semaste}
99254721Semaste
100314564Sdimvoid TypeList::RemoveMismatchedTypes(const char *qualified_typename,
101314564Sdim                                     bool exact_match) {
102314564Sdim  llvm::StringRef type_scope;
103314564Sdim  llvm::StringRef type_basename;
104314564Sdim  TypeClass type_class = eTypeClassAny;
105314564Sdim  if (!Type::GetTypeScopeAndBasename(qualified_typename, type_scope,
106314564Sdim                                     type_basename, type_class)) {
107314564Sdim    type_basename = qualified_typename;
108314564Sdim    type_scope = "";
109314564Sdim  }
110314564Sdim  return RemoveMismatchedTypes(type_scope, type_basename, type_class,
111314564Sdim                               exact_match);
112254721Semaste}
113254721Semaste
114314564Sdimvoid TypeList::RemoveMismatchedTypes(const std::string &type_scope,
115314564Sdim                                     const std::string &type_basename,
116314564Sdim                                     TypeClass type_class, bool exact_match) {
117341825Sdim  // Our "collection" type currently is a std::map which doesn't have any good
118341825Sdim  // way to iterate and remove items from the map so we currently just make a
119341825Sdim  // new list and add all of the matching types to it, and then swap it into
120341825Sdim  // m_types at the end
121314564Sdim  collection matching_types;
122254721Semaste
123314564Sdim  iterator pos, end = m_types.end();
124254721Semaste
125314564Sdim  for (pos = m_types.begin(); pos != end; ++pos) {
126314564Sdim    Type *the_type = pos->get();
127314564Sdim    bool keep_match = false;
128314564Sdim    TypeClass match_type_class = eTypeClassAny;
129254721Semaste
130314564Sdim    if (type_class != eTypeClassAny) {
131314564Sdim      match_type_class = the_type->GetForwardCompilerType().GetTypeClass();
132314564Sdim      if ((match_type_class & type_class) == 0)
133314564Sdim        continue;
134314564Sdim    }
135314564Sdim
136314564Sdim    ConstString match_type_name_const_str(the_type->GetQualifiedName());
137314564Sdim    if (match_type_name_const_str) {
138314564Sdim      const char *match_type_name = match_type_name_const_str.GetCString();
139314564Sdim      llvm::StringRef match_type_scope;
140314564Sdim      llvm::StringRef match_type_basename;
141314564Sdim      if (Type::GetTypeScopeAndBasename(match_type_name, match_type_scope,
142314564Sdim                                        match_type_basename,
143314564Sdim                                        match_type_class)) {
144314564Sdim        if (match_type_basename == type_basename) {
145314564Sdim          const size_t type_scope_size = type_scope.size();
146314564Sdim          const size_t match_type_scope_size = match_type_scope.size();
147314564Sdim          if (exact_match || (type_scope_size == match_type_scope_size)) {
148314564Sdim            keep_match = match_type_scope == type_scope;
149314564Sdim          } else {
150314564Sdim            if (match_type_scope_size > type_scope_size) {
151314564Sdim              const size_t type_scope_pos = match_type_scope.rfind(type_scope);
152314564Sdim              if (type_scope_pos == match_type_scope_size - type_scope_size) {
153314564Sdim                if (type_scope_pos >= 2) {
154314564Sdim                  // Our match scope ends with the type scope we were looking
155341825Sdim                  // for, but we need to make sure what comes before the
156341825Sdim                  // matching type scope is a namespace boundary in case we are
157341825Sdim                  // trying to match: type_basename = "d" type_scope = "b::c::"
158314564Sdim                  // We want to match:
159314564Sdim                  //  match_type_scope "a::b::c::"
160314564Sdim                  // But not:
161314564Sdim                  //  match_type_scope "a::bb::c::"
162314564Sdim                  // So below we make sure what comes before "b::c::" in
163341825Sdim                  // match_type_scope is "::", or the namespace boundary
164314564Sdim                  if (match_type_scope[type_scope_pos - 1] == ':' &&
165314564Sdim                      match_type_scope[type_scope_pos - 2] == ':') {
166314564Sdim                    keep_match = true;
167314564Sdim                  }
168254721Semaste                }
169314564Sdim              }
170254721Semaste            }
171314564Sdim          }
172254721Semaste        }
173314564Sdim      } else {
174341825Sdim        // The type we are currently looking at doesn't exists in a namespace
175341825Sdim        // or class, so it only matches if there is no type scope...
176344779Sdim        keep_match = type_scope.empty() && type_basename == match_type_name;
177314564Sdim      }
178254721Semaste    }
179314564Sdim
180314564Sdim    if (keep_match) {
181314564Sdim      matching_types.push_back(*pos);
182314564Sdim    }
183314564Sdim  }
184314564Sdim  m_types.swap(matching_types);
185254721Semaste}
186254721Semaste
187314564Sdimvoid TypeList::RemoveMismatchedTypes(TypeClass type_class) {
188314564Sdim  if (type_class == eTypeClassAny)
189314564Sdim    return;
190254721Semaste
191341825Sdim  // Our "collection" type currently is a std::map which doesn't have any good
192341825Sdim  // way to iterate and remove items from the map so we currently just make a
193341825Sdim  // new list and add all of the matching types to it, and then swap it into
194341825Sdim  // m_types at the end
195314564Sdim  collection matching_types;
196314564Sdim
197314564Sdim  iterator pos, end = m_types.end();
198314564Sdim
199314564Sdim  for (pos = m_types.begin(); pos != end; ++pos) {
200314564Sdim    Type *the_type = pos->get();
201314564Sdim    TypeClass match_type_class =
202314564Sdim        the_type->GetForwardCompilerType().GetTypeClass();
203314564Sdim    if (match_type_class & type_class)
204314564Sdim      matching_types.push_back(*pos);
205314564Sdim  }
206314564Sdim  m_types.swap(matching_types);
207254721Semaste}
208