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(g_initialize, [] {
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(g_initialize, [] {
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(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([&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(g_initialize, [] {
105    for (unsigned lang = eLanguageTypeUnknown; lang < eNumLanguageTypes;
106         ++lang) {
107      FindPlugin(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(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    {"unknown", eLanguageTypeUnknown},
162    {"c89", eLanguageTypeC89},
163    {"c", eLanguageTypeC},
164    {"ada83", eLanguageTypeAda83},
165    {"c++", eLanguageTypeC_plus_plus},
166    {"cobol74", eLanguageTypeCobol74},
167    {"cobol85", eLanguageTypeCobol85},
168    {"fortran77", eLanguageTypeFortran77},
169    {"fortran90", eLanguageTypeFortran90},
170    {"pascal83", eLanguageTypePascal83},
171    {"modula2", eLanguageTypeModula2},
172    {"java", eLanguageTypeJava},
173    {"c99", eLanguageTypeC99},
174    {"ada95", eLanguageTypeAda95},
175    {"fortran95", eLanguageTypeFortran95},
176    {"pli", eLanguageTypePLI},
177    {"objective-c", eLanguageTypeObjC},
178    {"objective-c++", eLanguageTypeObjC_plus_plus},
179    {"upc", eLanguageTypeUPC},
180    {"d", eLanguageTypeD},
181    {"python", eLanguageTypePython},
182    {"opencl", eLanguageTypeOpenCL},
183    {"go", eLanguageTypeGo},
184    {"modula3", eLanguageTypeModula3},
185    {"haskell", eLanguageTypeHaskell},
186    {"c++03", eLanguageTypeC_plus_plus_03},
187    {"c++11", eLanguageTypeC_plus_plus_11},
188    {"ocaml", eLanguageTypeOCaml},
189    {"rust", eLanguageTypeRust},
190    {"c11", eLanguageTypeC11},
191    {"swift", eLanguageTypeSwift},
192    {"julia", eLanguageTypeJulia},
193    {"dylan", eLanguageTypeDylan},
194    {"c++14", eLanguageTypeC_plus_plus_14},
195    {"fortran03", eLanguageTypeFortran03},
196    {"fortran08", eLanguageTypeFortran08},
197    {"renderscript", eLanguageTypeRenderScript},
198    {"bliss", eLanguageTypeBLISS},
199    {"kotlin", eLanguageTypeKotlin},
200    {"zig", eLanguageTypeZig},
201    {"crystal", eLanguageTypeCrystal},
202    {"<invalid language>",
203     static_cast<LanguageType>(
204         0x0029)}, // Not yet taken by any language in the DWARF spec
205                   // and thus has no entry in LanguageType
206    {"c++17", eLanguageTypeC_plus_plus_17},
207    {"c++20", eLanguageTypeC_plus_plus_20},
208    {"c17", eLanguageTypeC17},
209    {"fortran18", eLanguageTypeFortran18},
210    {"ada2005", eLanguageTypeAda2005},
211    {"ada2012", eLanguageTypeAda2012},
212    {"HIP", eLanguageTypeHIP},
213    {"assembly", eLanguageTypeAssembly},
214    {"c-sharp", eLanguageTypeC_sharp},
215    {"mojo", eLanguageTypeMojo},
216    // Vendor Extensions
217    {"assembler", eLanguageTypeMipsAssembler},
218    // Now synonyms, in arbitrary order
219    {"objc", eLanguageTypeObjC},
220    {"objc++", eLanguageTypeObjC_plus_plus},
221    {"pascal", 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(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("%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([&](Language *lang) {
387    supported_languages.emplace(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(nullptr, query, type_results);
440    for (const auto &match : type_results.GetTypeMap().Types()) {
441      if (match) {
442        CompilerType compiler_type(match->GetFullCompilerType());
443        compiler_type = AdjustForInclusion(compiler_type);
444        if (!compiler_type)
445          continue;
446        std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
447            new Result(compiler_type));
448        results.insert(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(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("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