1//===-- Language.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 <functional>
10#include <map>
11#include <mutex>
12
13#include "lldb/Target/Language.h"
14
15#include "lldb/Core/PluginManager.h"
16#include "lldb/Symbol/SymbolFile.h"
17#include "lldb/Symbol/TypeList.h"
18#include "lldb/Target/Target.h"
19#include "lldb/Utility/Stream.h"
20
21#include "llvm/Support/Threading.h"
22
23using namespace lldb;
24using namespace lldb_private;
25using namespace lldb_private::formatters;
26
27typedef std::unique_ptr<Language> LanguageUP;
28typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap;
29
30static LanguagesMap &GetLanguagesMap() {
31 static LanguagesMap *g_map = nullptr;
32 static llvm::once_flag g_initialize;
33
34 llvm::call_once(flag&: g_initialize, F: [] {
35 g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global
36 // destructor chain
37 });
38
39 return *g_map;
40}
41static std::mutex &GetLanguagesMutex() {
42 static std::mutex *g_mutex = nullptr;
43 static llvm::once_flag g_initialize;
44
45 llvm::call_once(flag&: g_initialize, F: [] {
46 g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global
47 // destructor chain
48 });
49
50 return *g_mutex;
51}
52
53Language *Language::FindPlugin(lldb::LanguageType language) {
54 std::lock_guard<std::mutex> guard(GetLanguagesMutex());
55 LanguagesMap &map(GetLanguagesMap());
56 auto iter = map.find(x: language), end = map.end();
57 if (iter != end)
58 return iter->second.get();
59
60 Language *language_ptr = nullptr;
61 LanguageCreateInstance create_callback;
62
63 for (uint32_t idx = 0;
64 (create_callback =
65 PluginManager::GetLanguageCreateCallbackAtIndex(idx)) != nullptr;
66 ++idx) {
67 language_ptr = create_callback(language);
68
69 if (language_ptr) {
70 map[language] = std::unique_ptr<Language>(language_ptr);
71 return language_ptr;
72 }
73 }
74
75 return nullptr;
76}
77
78Language *Language::FindPlugin(llvm::StringRef file_path) {
79 Language *result = nullptr;
80 ForEach(callback: [&result, file_path](Language *language) {
81 if (language->IsSourceFile(file_path)) {
82 result = language;
83 return false;
84 }
85 return true;
86 });
87 return result;
88}
89
90Language *Language::FindPlugin(LanguageType language,
91 llvm::StringRef file_path) {
92 Language *result = FindPlugin(language);
93 // Finding a language by file path is slower, we so we use this as the
94 // fallback.
95 if (!result)
96 result = FindPlugin(file_path);
97 return result;
98}
99
100void Language::ForEach(std::function<bool(Language *)> callback) {
101 // If we want to iterate over all languages, we first have to complete the
102 // LanguagesMap.
103 static llvm::once_flag g_initialize;
104 llvm::call_once(flag&: g_initialize, F: [] {
105 for (unsigned lang = eLanguageTypeUnknown; lang < eNumLanguageTypes;
106 ++lang) {
107 FindPlugin(language: static_cast<lldb::LanguageType>(lang));
108 }
109 });
110
111 // callback may call a method in Language that attempts to acquire the same
112 // lock (such as Language::ForEach or Language::FindPlugin). To avoid a
113 // deadlock, we do not use callback while holding the lock.
114 std::vector<Language *> loaded_plugins;
115 {
116 std::lock_guard<std::mutex> guard(GetLanguagesMutex());
117 LanguagesMap &map(GetLanguagesMap());
118 for (const auto &entry : map) {
119 if (entry.second)
120 loaded_plugins.push_back(x: entry.second.get());
121 }
122 }
123
124 for (auto *lang : loaded_plugins) {
125 if (!callback(lang))
126 break;
127 }
128}
129
130bool Language::IsTopLevelFunction(Function &function) { return false; }
131
132lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
133
134HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() {
135 return {};
136}
137
138HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() {
139 return {};
140}
141
142HardcodedFormatters::HardcodedSyntheticFinder
143Language::GetHardcodedSynthetics() {
144 return {};
145}
146
147std::vector<FormattersMatchCandidate>
148Language::GetPossibleFormattersMatches(ValueObject &valobj,
149 lldb::DynamicValueType use_dynamic) {
150 return {};
151}
152
153struct language_name_pair {
154 const char *name;
155 LanguageType type;
156};
157
158struct language_name_pair language_names[] = {
159 // To allow GetNameForLanguageType to be a simple array lookup, the first
160 // part of this array must follow enum LanguageType exactly.
161 {.name: "unknown", .type: eLanguageTypeUnknown},
162 {.name: "c89", .type: eLanguageTypeC89},
163 {.name: "c", .type: eLanguageTypeC},
164 {.name: "ada83", .type: eLanguageTypeAda83},
165 {.name: "c++", .type: eLanguageTypeC_plus_plus},
166 {.name: "cobol74", .type: eLanguageTypeCobol74},
167 {.name: "cobol85", .type: eLanguageTypeCobol85},
168 {.name: "fortran77", .type: eLanguageTypeFortran77},
169 {.name: "fortran90", .type: eLanguageTypeFortran90},
170 {.name: "pascal83", .type: eLanguageTypePascal83},
171 {.name: "modula2", .type: eLanguageTypeModula2},
172 {.name: "java", .type: eLanguageTypeJava},
173 {.name: "c99", .type: eLanguageTypeC99},
174 {.name: "ada95", .type: eLanguageTypeAda95},
175 {.name: "fortran95", .type: eLanguageTypeFortran95},
176 {.name: "pli", .type: eLanguageTypePLI},
177 {.name: "objective-c", .type: eLanguageTypeObjC},
178 {.name: "objective-c++", .type: eLanguageTypeObjC_plus_plus},
179 {.name: "upc", .type: eLanguageTypeUPC},
180 {.name: "d", .type: eLanguageTypeD},
181 {.name: "python", .type: eLanguageTypePython},
182 {.name: "opencl", .type: eLanguageTypeOpenCL},
183 {.name: "go", .type: eLanguageTypeGo},
184 {.name: "modula3", .type: eLanguageTypeModula3},
185 {.name: "haskell", .type: eLanguageTypeHaskell},
186 {.name: "c++03", .type: eLanguageTypeC_plus_plus_03},
187 {.name: "c++11", .type: eLanguageTypeC_plus_plus_11},
188 {.name: "ocaml", .type: eLanguageTypeOCaml},
189 {.name: "rust", .type: eLanguageTypeRust},
190 {.name: "c11", .type: eLanguageTypeC11},
191 {.name: "swift", .type: eLanguageTypeSwift},
192 {.name: "julia", .type: eLanguageTypeJulia},
193 {.name: "dylan", .type: eLanguageTypeDylan},
194 {.name: "c++14", .type: eLanguageTypeC_plus_plus_14},
195 {.name: "fortran03", .type: eLanguageTypeFortran03},
196 {.name: "fortran08", .type: eLanguageTypeFortran08},
197 {.name: "renderscript", .type: eLanguageTypeRenderScript},
198 {.name: "bliss", .type: eLanguageTypeBLISS},
199 {.name: "kotlin", .type: eLanguageTypeKotlin},
200 {.name: "zig", .type: eLanguageTypeZig},
201 {.name: "crystal", .type: eLanguageTypeCrystal},
202 {.name: "<invalid language>",
203 .type: static_cast<LanguageType>(
204 0x0029)}, // Not yet taken by any language in the DWARF spec
205 // and thus has no entry in LanguageType
206 {.name: "c++17", .type: eLanguageTypeC_plus_plus_17},
207 {.name: "c++20", .type: eLanguageTypeC_plus_plus_20},
208 {.name: "c17", .type: eLanguageTypeC17},
209 {.name: "fortran18", .type: eLanguageTypeFortran18},
210 {.name: "ada2005", .type: eLanguageTypeAda2005},
211 {.name: "ada2012", .type: eLanguageTypeAda2012},
212 {.name: "HIP", .type: eLanguageTypeHIP},
213 {.name: "assembly", .type: eLanguageTypeAssembly},
214 {.name: "c-sharp", .type: eLanguageTypeC_sharp},
215 {.name: "mojo", .type: eLanguageTypeMojo},
216 // Vendor Extensions
217 {.name: "assembler", .type: eLanguageTypeMipsAssembler},
218 // Now synonyms, in arbitrary order
219 {.name: "objc", .type: eLanguageTypeObjC},
220 {.name: "objc++", .type: eLanguageTypeObjC_plus_plus},
221 {.name: "pascal", .type: eLanguageTypePascal83}};
222
223static uint32_t num_languages =
224 sizeof(language_names) / sizeof(struct language_name_pair);
225
226LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
227 for (const auto &L : language_names) {
228 if (string.equals_insensitive(RHS: L.name))
229 return static_cast<LanguageType>(L.type);
230 }
231
232 return eLanguageTypeUnknown;
233}
234
235const char *Language::GetNameForLanguageType(LanguageType language) {
236 if (language < num_languages)
237 return language_names[language].name;
238 else
239 return language_names[eLanguageTypeUnknown].name;
240}
241
242void Language::PrintSupportedLanguagesForExpressions(Stream &s,
243 llvm::StringRef prefix,
244 llvm::StringRef suffix) {
245 auto supported = Language::GetLanguagesSupportingTypeSystemsForExpressions();
246 for (size_t idx = 0; idx < num_languages; ++idx) {
247 auto const &lang = language_names[idx];
248 if (supported[lang.type])
249 s << prefix << lang.name << suffix;
250 }
251}
252
253void Language::PrintAllLanguages(Stream &s, const char *prefix,
254 const char *suffix) {
255 for (uint32_t i = 1; i < num_languages; i++) {
256 s.Printf(format: "%s%s%s", prefix, language_names[i].name, suffix);
257 }
258}
259
260void Language::ForAllLanguages(
261 std::function<bool(lldb::LanguageType)> callback) {
262 for (uint32_t i = 1; i < num_languages; i++) {
263 if (!callback(language_names[i].type))
264 break;
265 }
266}
267
268bool Language::LanguageIsCPlusPlus(LanguageType language) {
269 switch (language) {
270 case eLanguageTypeC_plus_plus:
271 case eLanguageTypeC_plus_plus_03:
272 case eLanguageTypeC_plus_plus_11:
273 case eLanguageTypeC_plus_plus_14:
274 case eLanguageTypeC_plus_plus_17:
275 case eLanguageTypeC_plus_plus_20:
276 case eLanguageTypeObjC_plus_plus:
277 return true;
278 default:
279 return false;
280 }
281}
282
283bool Language::LanguageIsObjC(LanguageType language) {
284 switch (language) {
285 case eLanguageTypeObjC:
286 case eLanguageTypeObjC_plus_plus:
287 return true;
288 default:
289 return false;
290 }
291}
292
293bool Language::LanguageIsC(LanguageType language) {
294 switch (language) {
295 case eLanguageTypeC:
296 case eLanguageTypeC89:
297 case eLanguageTypeC99:
298 case eLanguageTypeC11:
299 return true;
300 default:
301 return false;
302 }
303}
304
305bool Language::LanguageIsCFamily(LanguageType language) {
306 switch (language) {
307 case eLanguageTypeC:
308 case eLanguageTypeC89:
309 case eLanguageTypeC99:
310 case eLanguageTypeC11:
311 case eLanguageTypeC_plus_plus:
312 case eLanguageTypeC_plus_plus_03:
313 case eLanguageTypeC_plus_plus_11:
314 case eLanguageTypeC_plus_plus_14:
315 case eLanguageTypeC_plus_plus_17:
316 case eLanguageTypeC_plus_plus_20:
317 case eLanguageTypeObjC_plus_plus:
318 case eLanguageTypeObjC:
319 return true;
320 default:
321 return false;
322 }
323}
324
325bool Language::LanguageIsPascal(LanguageType language) {
326 switch (language) {
327 case eLanguageTypePascal83:
328 return true;
329 default:
330 return false;
331 }
332}
333
334LanguageType Language::GetPrimaryLanguage(LanguageType language) {
335 switch (language) {
336 case eLanguageTypeC_plus_plus:
337 case eLanguageTypeC_plus_plus_03:
338 case eLanguageTypeC_plus_plus_11:
339 case eLanguageTypeC_plus_plus_14:
340 case eLanguageTypeC_plus_plus_17:
341 case eLanguageTypeC_plus_plus_20:
342 return eLanguageTypeC_plus_plus;
343 case eLanguageTypeC:
344 case eLanguageTypeC89:
345 case eLanguageTypeC99:
346 case eLanguageTypeC11:
347 return eLanguageTypeC;
348 case eLanguageTypeObjC:
349 case eLanguageTypeObjC_plus_plus:
350 return eLanguageTypeObjC;
351 case eLanguageTypePascal83:
352 case eLanguageTypeCobol74:
353 case eLanguageTypeCobol85:
354 case eLanguageTypeFortran77:
355 case eLanguageTypeFortran90:
356 case eLanguageTypeFortran95:
357 case eLanguageTypeFortran03:
358 case eLanguageTypeFortran08:
359 case eLanguageTypeAda83:
360 case eLanguageTypeAda95:
361 case eLanguageTypeModula2:
362 case eLanguageTypeJava:
363 case eLanguageTypePLI:
364 case eLanguageTypeUPC:
365 case eLanguageTypeD:
366 case eLanguageTypePython:
367 case eLanguageTypeOpenCL:
368 case eLanguageTypeGo:
369 case eLanguageTypeModula3:
370 case eLanguageTypeHaskell:
371 case eLanguageTypeOCaml:
372 case eLanguageTypeRust:
373 case eLanguageTypeSwift:
374 case eLanguageTypeJulia:
375 case eLanguageTypeDylan:
376 case eLanguageTypeMipsAssembler:
377 case eLanguageTypeMojo:
378 case eLanguageTypeUnknown:
379 default:
380 return language;
381 }
382}
383
384std::set<lldb::LanguageType> Language::GetSupportedLanguages() {
385 std::set<lldb::LanguageType> supported_languages;
386 ForEach(callback: [&](Language *lang) {
387 supported_languages.emplace(args: lang->GetLanguageType());
388 return true;
389 });
390 return supported_languages;
391}
392
393LanguageSet Language::GetLanguagesSupportingTypeSystems() {
394 return PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
395}
396
397LanguageSet Language::GetLanguagesSupportingTypeSystemsForExpressions() {
398 return PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions();
399}
400
401LanguageSet Language::GetLanguagesSupportingREPLs() {
402 return PluginManager::GetREPLAllTypeSystemSupportedLanguages();
403}
404
405std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
406 return nullptr;
407}
408
409const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
410
411size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope,
412 const char *key, ResultSet &results,
413 bool append) {
414 if (!exe_scope || !exe_scope->CalculateTarget().get())
415 return false;
416
417 if (!key || !key[0])
418 return false;
419
420 if (!append)
421 results.clear();
422
423 size_t old_size = results.size();
424
425 if (this->Find_Impl(exe_scope, key, results))
426 return results.size() - old_size;
427 return 0;
428}
429
430bool Language::ImageListTypeScavenger::Find_Impl(
431 ExecutionContextScope *exe_scope, const char *key, ResultSet &results) {
432 bool result = false;
433
434 Target *target = exe_scope->CalculateTarget().get();
435 if (target) {
436 const auto &images(target->GetImages());
437 TypeQuery query(key);
438 TypeResults type_results;
439 images.FindTypes(search_first: nullptr, query, results&: type_results);
440 for (const auto &match : type_results.GetTypeMap().Types()) {
441 if (match) {
442 CompilerType compiler_type(match->GetFullCompilerType());
443 compiler_type = AdjustForInclusion(candidate&: compiler_type);
444 if (!compiler_type)
445 continue;
446 std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
447 new Result(compiler_type));
448 results.insert(x: std::move(scavengeresult));
449 result = true;
450 }
451 }
452 }
453
454 return result;
455}
456
457std::pair<llvm::StringRef, llvm::StringRef>
458Language::GetFormatterPrefixSuffix(llvm::StringRef type_hint) {
459 return std::pair<llvm::StringRef, llvm::StringRef>();
460}
461
462bool Language::DemangledNameContainsPath(llvm::StringRef path,
463 ConstString demangled) const {
464 // The base implementation does a simple contains comparision:
465 if (path.empty())
466 return false;
467 return demangled.GetStringRef().contains(Other: path);
468}
469
470DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
471 return nullptr;
472}
473
474LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
475 return eLazyBoolCalculate;
476}
477
478bool Language::IsNilReference(ValueObject &valobj) { return false; }
479
480bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
481
482bool Language::GetFunctionDisplayName(const SymbolContext *sc,
483 const ExecutionContext *exe_ctx,
484 FunctionNameRepresentation representation,
485 Stream &s) {
486 return false;
487}
488
489void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
490 Stream &s) {
491 GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
492}
493
494void Language::GetDefaultExceptionResolverDescription(bool catch_on,
495 bool throw_on,
496 Stream &s) {
497 s.Printf(format: "Exception breakpoint (catch: %s throw: %s)",
498 catch_on ? "on" : "off", throw_on ? "on" : "off");
499}
500// Constructor
501Language::Language() = default;
502
503// Destructor
504Language::~Language() = default;
505

source code of lldb/source/Target/Language.cpp