1 //===-- TypeMap.cpp --------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 
11 // C Includes
12 // C++ Includes
13 #include <vector>
14 
15 // Other libraries and framework includes
16 #include "clang/AST/ASTConsumer.h"
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/AST/DeclGroup.h"
21 
22 #include "clang/Basic/Builtins.h"
23 #include "clang/Basic/IdentifierTable.h"
24 #include "clang/Basic/LangOptions.h"
25 #include "clang/Basic/SourceManager.h"
26 #include "clang/Basic/TargetInfo.h"
27 
28 #include "llvm/Support/FormattedStream.h"
29 #include "llvm/Support/raw_ostream.h"
30 
31 // Project includes
32 #include "lldb/Symbol/SymbolFile.h"
33 #include "lldb/Symbol/SymbolVendor.h"
34 #include "lldb/Symbol/Type.h"
35 #include "lldb/Symbol/TypeMap.h"
36 
37 using namespace lldb;
38 using namespace lldb_private;
39 using namespace clang;
40 
41 TypeMap::TypeMap() :
42     m_types ()
43 {
44 }
45 
46 //----------------------------------------------------------------------
47 // Destructor
48 //----------------------------------------------------------------------
49 TypeMap::~TypeMap()
50 {
51 }
52 
53 void
54 TypeMap::Insert (const TypeSP& type_sp)
55 {
56     // Just push each type on the back for now. We will worry about uniquing later
57     if (type_sp)
58         m_types.insert(std::make_pair(type_sp->GetID(), type_sp));
59 }
60 
61 
62 bool
63 TypeMap::InsertUnique (const TypeSP& type_sp)
64 {
65     if (type_sp)
66     {
67         user_id_t type_uid = type_sp->GetID();
68         iterator pos, end = m_types.end();
69 
70         for (pos = m_types.find(type_uid); pos != end && pos->second->GetID() == type_uid; ++pos)
71         {
72             if (pos->second.get() == type_sp.get())
73                 return false;
74         }
75         Insert (type_sp);
76     }
77     return true;
78 }
79 
80 //----------------------------------------------------------------------
81 // Find a base type by its unique ID.
82 //----------------------------------------------------------------------
83 //TypeSP
84 //TypeMap::FindType(lldb::user_id_t uid)
85 //{
86 //    iterator pos = m_types.find(uid);
87 //    if (pos != m_types.end())
88 //        return pos->second;
89 //    return TypeSP();
90 //}
91 
92 //----------------------------------------------------------------------
93 // Find a type by name.
94 //----------------------------------------------------------------------
95 //TypeMap
96 //TypeMap::FindTypes (const ConstString &name)
97 //{
98 //    // Do we ever need to make a lookup by name map? Here we are doing
99 //    // a linear search which isn't going to be fast.
100 //    TypeMap types(m_ast.getTargetInfo()->getTriple().getTriple().c_str());
101 //    iterator pos, end;
102 //    for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
103 //        if (pos->second->GetName() == name)
104 //            types.Insert (pos->second);
105 //    return types;
106 //}
107 
108 void
109 TypeMap::Clear()
110 {
111     m_types.clear();
112 }
113 
114 uint32_t
115 TypeMap::GetSize() const
116 {
117     return m_types.size();
118 }
119 
120 bool
121 TypeMap::Empty() const
122 {
123     return m_types.empty();
124 }
125 
126 // GetTypeAtIndex isn't used a lot for large type lists, currently only for
127 // type lists that are returned for "image dump -t TYPENAME" commands and other
128 // simple symbol queries that grab the first result...
129 
130 TypeSP
131 TypeMap::GetTypeAtIndex(uint32_t idx)
132 {
133     iterator pos, end;
134     uint32_t i = idx;
135     for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
136     {
137         if (i == 0)
138             return pos->second;
139         --i;
140     }
141     return TypeSP();
142 }
143 
144 void
145 TypeMap::ForEach (std::function <bool(const lldb::TypeSP &type_sp)> const &callback) const
146 {
147     for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
148     {
149         if (!callback(pos->second))
150             break;
151     }
152 }
153 
154 void
155 TypeMap::ForEach (std::function <bool(lldb::TypeSP &type_sp)> const &callback)
156 {
157     for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
158     {
159         if (!callback(pos->second))
160             break;
161     }
162 }
163 
164 bool
165 TypeMap::Remove (const lldb::TypeSP &type_sp)
166 {
167     if (type_sp)
168     {
169         lldb::user_id_t uid = type_sp->GetID();
170         for (iterator pos = m_types.find(uid), end = m_types.end(); pos != end && pos->first == uid; ++pos)
171         {
172             if (pos->second == type_sp)
173             {
174                 m_types.erase(pos);
175                 return true;
176             }
177         }
178     }
179     return false;
180 }
181 
182 void
183 TypeMap::Dump(Stream *s, bool show_context)
184 {
185     for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
186     {
187         pos->second->Dump(s, show_context);
188     }
189 }
190 
191 void
192 TypeMap::RemoveMismatchedTypes (const char *qualified_typename,
193                                  bool exact_match)
194 {
195     std::string type_scope;
196     std::string type_basename;
197     TypeClass type_class = eTypeClassAny;
198     if (!Type::GetTypeScopeAndBasename (qualified_typename, type_scope, type_basename, type_class))
199     {
200         type_basename = qualified_typename;
201         type_scope.clear();
202     }
203     return RemoveMismatchedTypes (type_scope, type_basename, type_class, exact_match);
204 }
205 
206 void
207 TypeMap::RemoveMismatchedTypes (const std::string &type_scope,
208                                  const std::string &type_basename,
209                                  TypeClass type_class,
210                                  bool exact_match)
211 {
212     // Our "collection" type currently is a std::map which doesn't
213     // have any good way to iterate and remove items from the map
214     // so we currently just make a new list and add all of the matching
215     // types to it, and then swap it into m_types at the end
216     collection matching_types;
217 
218     iterator pos, end = m_types.end();
219 
220     for (pos = m_types.begin(); pos != end; ++pos)
221     {
222         Type* the_type = pos->second.get();
223         bool keep_match = false;
224         TypeClass match_type_class = eTypeClassAny;
225 
226         if (type_class != eTypeClassAny)
227         {
228             match_type_class = the_type->GetForwardCompilerType ().GetTypeClass ();
229             if ((match_type_class & type_class) == 0)
230                 continue;
231         }
232 
233         ConstString match_type_name_const_str (the_type->GetQualifiedName());
234         if (match_type_name_const_str)
235         {
236             const char *match_type_name = match_type_name_const_str.GetCString();
237             std::string match_type_scope;
238             std::string match_type_basename;
239             if (Type::GetTypeScopeAndBasename (match_type_name,
240                                                match_type_scope,
241                                                match_type_basename,
242                                                match_type_class))
243             {
244                 if (match_type_basename == type_basename)
245                 {
246                     const size_t type_scope_size = type_scope.size();
247                     const size_t match_type_scope_size = match_type_scope.size();
248                     if (exact_match || (type_scope_size == match_type_scope_size))
249                     {
250                         keep_match = match_type_scope == type_scope;
251                     }
252                     else
253                     {
254                         if (match_type_scope_size > type_scope_size)
255                         {
256                             const size_t type_scope_pos = match_type_scope.rfind(type_scope);
257                             if (type_scope_pos == match_type_scope_size - type_scope_size)
258                             {
259                                 if (type_scope_pos >= 2)
260                                 {
261                                     // Our match scope ends with the type scope we were looking for,
262                                     // but we need to make sure what comes before the matching
263                                     // type scope is a namespace boundary in case we are trying to match:
264                                     // type_basename = "d"
265                                     // type_scope = "b::c::"
266                                     // We want to match:
267                                     //  match_type_scope "a::b::c::"
268                                     // But not:
269                                     //  match_type_scope "a::bb::c::"
270                                     // So below we make sure what comes before "b::c::" in match_type_scope
271                                     // is "::", or the namespace boundary
272                                     if (match_type_scope[type_scope_pos - 1] == ':' &&
273                                         match_type_scope[type_scope_pos - 2] == ':')
274                                     {
275                                         keep_match = true;
276                                     }
277                                 }
278                             }
279                         }
280                     }
281                 }
282             }
283             else
284             {
285                 // The type we are currently looking at doesn't exists
286                 // in a namespace or class, so it only matches if there
287                 // is no type scope...
288                 keep_match = type_scope.empty() && type_basename.compare(match_type_name) == 0;
289             }
290         }
291 
292         if (keep_match)
293         {
294             matching_types.insert (*pos);
295         }
296     }
297     m_types.swap(matching_types);
298 }
299 
300 void
301 TypeMap::RemoveMismatchedTypes (TypeClass type_class)
302 {
303     if (type_class == eTypeClassAny)
304         return;
305 
306     // Our "collection" type currently is a std::map which doesn't
307     // have any good way to iterate and remove items from the map
308     // so we currently just make a new list and add all of the matching
309     // types to it, and then swap it into m_types at the end
310     collection matching_types;
311 
312     iterator pos, end = m_types.end();
313 
314     for (pos = m_types.begin(); pos != end; ++pos)
315     {
316         Type* the_type = pos->second.get();
317         TypeClass match_type_class = the_type->GetForwardCompilerType ().GetTypeClass ();
318         if (match_type_class & type_class)
319             matching_types.insert (*pos);
320     }
321     m_types.swap(matching_types);
322 }
323