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

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