1 //===-- TypeSystem.cpp ------------------------------------------*- C++ -*-===//
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 //
10 //  TypeSystem.cpp
11 //  lldb
12 //
13 //  Created by Ryan Brown on 3/29/15.
14 //
15 //
16 
17 #include "lldb/Symbol/TypeSystem.h"
18 
19 #include <set>
20 
21 #include "lldb/Core/PluginManager.h"
22 #include "lldb/Symbol/CompilerType.h"
23 #include "lldb/Target/Language.h"
24 
25 using namespace lldb_private;
26 using namespace lldb;
27 
28 TypeSystem::TypeSystem(LLVMCastKind kind) : m_kind(kind), m_sym_file(nullptr) {}
29 
30 TypeSystem::~TypeSystem() {}
31 
32 static lldb::TypeSystemSP CreateInstanceHelper(lldb::LanguageType language,
33                                                Module *module, Target *target) {
34   uint32_t i = 0;
35   TypeSystemCreateInstance create_callback;
36   while ((create_callback = PluginManager::GetTypeSystemCreateCallbackAtIndex(
37               i++)) != nullptr) {
38     lldb::TypeSystemSP type_system_sp =
39         create_callback(language, module, target);
40     if (type_system_sp)
41       return type_system_sp;
42   }
43 
44   return lldb::TypeSystemSP();
45 }
46 
47 lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
48                                               Module *module) {
49   return CreateInstanceHelper(language, module, nullptr);
50 }
51 
52 lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
53                                               Target *target) {
54   return CreateInstanceHelper(language, nullptr, target);
55 }
56 
57 bool TypeSystem::IsAnonymousType(lldb::opaque_compiler_type_t type) {
58   return false;
59 }
60 
61 CompilerType TypeSystem::GetArrayType(lldb::opaque_compiler_type_t type,
62                                       uint64_t size) {
63   return CompilerType();
64 }
65 
66 CompilerType
67 TypeSystem::GetLValueReferenceType(lldb::opaque_compiler_type_t type) {
68   return CompilerType();
69 }
70 
71 CompilerType
72 TypeSystem::GetRValueReferenceType(lldb::opaque_compiler_type_t type) {
73   return CompilerType();
74 }
75 
76 CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) {
77   return CompilerType();
78 }
79 
80 CompilerType
81 TypeSystem::AddVolatileModifier(lldb::opaque_compiler_type_t type) {
82   return CompilerType();
83 }
84 
85 CompilerType
86 TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) {
87   return CompilerType();
88 }
89 
90 CompilerType TypeSystem::CreateTypedef(lldb::opaque_compiler_type_t type,
91                                        const char *name,
92                                        const CompilerDeclContext &decl_ctx) {
93   return CompilerType();
94 }
95 
96 CompilerType TypeSystem::GetBuiltinTypeByName(ConstString name) {
97   return CompilerType();
98 }
99 
100 CompilerType TypeSystem::GetTypeForFormatters(void *type) {
101   return CompilerType(this, type);
102 }
103 
104 size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
105   return 0;
106 }
107 
108 TemplateArgumentKind
109 TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx) {
110   return eTemplateArgumentKindNull;
111 }
112 
113 CompilerType TypeSystem::GetTypeTemplateArgument(opaque_compiler_type_t type,
114                                                  size_t idx) {
115   return CompilerType();
116 }
117 
118 llvm::Optional<CompilerType::IntegralTemplateArgument>
119 TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type,
120                                         size_t idx) {
121   return llvm::None;
122 }
123 
124 LazyBool TypeSystem::ShouldPrintAsOneLiner(void *type, ValueObject *valobj) {
125   return eLazyBoolCalculate;
126 }
127 
128 ConstString TypeSystem::DeclGetMangledName(void *opaque_decl) {
129   return ConstString();
130 }
131 
132 CompilerDeclContext TypeSystem::DeclGetDeclContext(void *opaque_decl) {
133   return CompilerDeclContext();
134 }
135 
136 CompilerType TypeSystem::DeclGetFunctionReturnType(void *opaque_decl) {
137   return CompilerType();
138 }
139 
140 size_t TypeSystem::DeclGetFunctionNumArguments(void *opaque_decl) { return 0; }
141 
142 CompilerType TypeSystem::DeclGetFunctionArgumentType(void *opaque_decl,
143                                                      size_t arg_idx) {
144   return CompilerType();
145 }
146 
147 std::vector<CompilerDecl>
148 TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
149                                       bool ignore_imported_decls) {
150   return std::vector<CompilerDecl>();
151 }
152 
153 #pragma mark TypeSystemMap
154 
155 TypeSystemMap::TypeSystemMap()
156     : m_mutex(), m_map(), m_clear_in_progress(false) {}
157 
158 TypeSystemMap::~TypeSystemMap() {}
159 
160 void TypeSystemMap::Clear() {
161   collection map;
162   {
163     std::lock_guard<std::mutex> guard(m_mutex);
164     map = m_map;
165     m_clear_in_progress = true;
166   }
167   std::set<TypeSystem *> visited;
168   for (auto pair : map) {
169     TypeSystem *type_system = pair.second.get();
170     if (type_system && !visited.count(type_system)) {
171       visited.insert(type_system);
172       type_system->Finalize();
173     }
174   }
175   map.clear();
176   {
177     std::lock_guard<std::mutex> guard(m_mutex);
178     m_map.clear();
179     m_clear_in_progress = false;
180   }
181 }
182 
183 void TypeSystemMap::ForEach(std::function<bool(TypeSystem *)> const &callback) {
184   std::lock_guard<std::mutex> guard(m_mutex);
185   // Use a std::set so we only call the callback once for each unique
186   // TypeSystem instance
187   std::set<TypeSystem *> visited;
188   for (auto pair : m_map) {
189     TypeSystem *type_system = pair.second.get();
190     if (type_system && !visited.count(type_system)) {
191       visited.insert(type_system);
192       if (!callback(type_system))
193         break;
194     }
195   }
196 }
197 
198 llvm::Expected<TypeSystem &>
199 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
200                                         Module *module, bool can_create) {
201   llvm::Error error = llvm::Error::success();
202   assert(!error); // Check the success value when assertions are enabled
203   std::lock_guard<std::mutex> guard(m_mutex);
204   if (m_clear_in_progress) {
205     error = llvm::make_error<llvm::StringError>(
206         "Unable to get TypeSystem because TypeSystemMap is being cleared",
207         llvm::inconvertibleErrorCode());
208   } else {
209     collection::iterator pos = m_map.find(language);
210     if (pos != m_map.end()) {
211       auto *type_system = pos->second.get();
212       if (type_system) {
213         llvm::consumeError(std::move(error));
214         return *type_system;
215       }
216       error = llvm::make_error<llvm::StringError>(
217           "TypeSystem for language " +
218               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
219               " doesn't exist",
220           llvm::inconvertibleErrorCode());
221       return std::move(error);
222     }
223 
224     for (const auto &pair : m_map) {
225       if (pair.second && pair.second->SupportsLanguage(language)) {
226         // Add a new mapping for "language" to point to an already existing
227         // TypeSystem that supports this language
228         m_map[language] = pair.second;
229         if (pair.second.get()) {
230           llvm::consumeError(std::move(error));
231           return *pair.second.get();
232         }
233         error = llvm::make_error<llvm::StringError>(
234             "TypeSystem for language " +
235                 llvm::toStringRef(Language::GetNameForLanguageType(language)) +
236                 " doesn't exist",
237             llvm::inconvertibleErrorCode());
238         return std::move(error);
239       }
240     }
241 
242     if (!can_create) {
243       error = llvm::make_error<llvm::StringError>(
244           "Unable to find type system for language " +
245               llvm::toStringRef(Language::GetNameForLanguageType(language)),
246           llvm::inconvertibleErrorCode());
247     } else {
248       // Cache even if we get a shared pointer that contains a null type system
249       // back
250       auto type_system_sp = TypeSystem::CreateInstance(language, module);
251       m_map[language] = type_system_sp;
252       if (type_system_sp.get()) {
253         llvm::consumeError(std::move(error));
254         return *type_system_sp.get();
255       }
256       error = llvm::make_error<llvm::StringError>(
257           "TypeSystem for language " +
258               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
259               " doesn't exist",
260           llvm::inconvertibleErrorCode());
261     }
262   }
263 
264   return std::move(error);
265 }
266 
267 llvm::Expected<TypeSystem &>
268 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
269                                         Target *target, bool can_create) {
270   llvm::Error error = llvm::Error::success();
271   assert(!error); // Check the success value when assertions are enabled
272   std::lock_guard<std::mutex> guard(m_mutex);
273   if (m_clear_in_progress) {
274     error = llvm::make_error<llvm::StringError>(
275         "Unable to get TypeSystem because TypeSystemMap is being cleared",
276         llvm::inconvertibleErrorCode());
277   } else {
278     collection::iterator pos = m_map.find(language);
279     if (pos != m_map.end()) {
280       auto *type_system = pos->second.get();
281       if (type_system) {
282         llvm::consumeError(std::move(error));
283         return *type_system;
284       }
285       error = llvm::make_error<llvm::StringError>(
286           "TypeSystem for language " +
287               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
288               " doesn't exist",
289           llvm::inconvertibleErrorCode());
290       return std::move(error);
291     }
292 
293     for (const auto &pair : m_map) {
294       if (pair.second && pair.second->SupportsLanguage(language)) {
295         // Add a new mapping for "language" to point to an already existing
296         // TypeSystem that supports this language
297         m_map[language] = pair.second;
298         if (pair.second.get()) {
299           llvm::consumeError(std::move(error));
300           return *pair.second.get();
301         }
302         error = llvm::make_error<llvm::StringError>(
303             "TypeSystem for language " +
304                 llvm::toStringRef(Language::GetNameForLanguageType(language)) +
305                 " doesn't exist",
306             llvm::inconvertibleErrorCode());
307         return std::move(error);
308       }
309     }
310 
311     if (!can_create) {
312       error = llvm::make_error<llvm::StringError>(
313           "Unable to find type system for language " +
314               llvm::toStringRef(Language::GetNameForLanguageType(language)),
315           llvm::inconvertibleErrorCode());
316     } else {
317       // Cache even if we get a shared pointer that contains a null type system
318       // back
319       auto type_system_sp = TypeSystem::CreateInstance(language, target);
320       m_map[language] = type_system_sp;
321       if (type_system_sp.get()) {
322         llvm::consumeError(std::move(error));
323         return *type_system_sp.get();
324       }
325       error = llvm::make_error<llvm::StringError>(
326           "TypeSystem for language " +
327               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
328               " doesn't exist",
329           llvm::inconvertibleErrorCode());
330     }
331   }
332 
333   return std::move(error);
334 }
335