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 
23 using namespace lldb;
24 using namespace lldb_private;
25 using namespace lldb_private::formatters;
26 
27 typedef std::unique_ptr<Language> LanguageUP;
28 typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap;
29 
30 static 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 }
41 static 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 
53 Language *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 
78 Language *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 
90 Language *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 
100 void 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   std::lock_guard<std::mutex> guard(GetLanguagesMutex());
112   LanguagesMap &map(GetLanguagesMap());
113   for (const auto &entry : map) {
114     if (!callback(entry.second.get()))
115       break;
116   }
117 }
118 
119 bool Language::IsTopLevelFunction(Function &function) { return false; }
120 
121 lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
122 
123 HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() {
124   return {};
125 }
126 
127 HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() {
128   return {};
129 }
130 
131 HardcodedFormatters::HardcodedSyntheticFinder
132 Language::GetHardcodedSynthetics() {
133   return {};
134 }
135 
136 std::vector<ConstString>
137 Language::GetPossibleFormattersMatches(ValueObject &valobj,
138                                        lldb::DynamicValueType use_dynamic) {
139   return {};
140 }
141 
142 lldb_private::formatters::StringPrinter::EscapingHelper
143 Language::GetStringPrinterEscapingHelper(
144     lldb_private::formatters::StringPrinter::GetPrintableElementType
145         elem_type) {
146   return StringPrinter::GetDefaultEscapingHelper(elem_type);
147 }
148 
149 struct language_name_pair {
150   const char *name;
151   LanguageType type;
152 };
153 
154 struct language_name_pair language_names[] = {
155     // To allow GetNameForLanguageType to be a simple array lookup, the first
156     // part of this array must follow enum LanguageType exactly.
157     {"unknown", eLanguageTypeUnknown},
158     {"c89", eLanguageTypeC89},
159     {"c", eLanguageTypeC},
160     {"ada83", eLanguageTypeAda83},
161     {"c++", eLanguageTypeC_plus_plus},
162     {"cobol74", eLanguageTypeCobol74},
163     {"cobol85", eLanguageTypeCobol85},
164     {"fortran77", eLanguageTypeFortran77},
165     {"fortran90", eLanguageTypeFortran90},
166     {"pascal83", eLanguageTypePascal83},
167     {"modula2", eLanguageTypeModula2},
168     {"java", eLanguageTypeJava},
169     {"c99", eLanguageTypeC99},
170     {"ada95", eLanguageTypeAda95},
171     {"fortran95", eLanguageTypeFortran95},
172     {"pli", eLanguageTypePLI},
173     {"objective-c", eLanguageTypeObjC},
174     {"objective-c++", eLanguageTypeObjC_plus_plus},
175     {"upc", eLanguageTypeUPC},
176     {"d", eLanguageTypeD},
177     {"python", eLanguageTypePython},
178     {"opencl", eLanguageTypeOpenCL},
179     {"go", eLanguageTypeGo},
180     {"modula3", eLanguageTypeModula3},
181     {"haskell", eLanguageTypeHaskell},
182     {"c++03", eLanguageTypeC_plus_plus_03},
183     {"c++11", eLanguageTypeC_plus_plus_11},
184     {"ocaml", eLanguageTypeOCaml},
185     {"rust", eLanguageTypeRust},
186     {"c11", eLanguageTypeC11},
187     {"swift", eLanguageTypeSwift},
188     {"julia", eLanguageTypeJulia},
189     {"dylan", eLanguageTypeDylan},
190     {"c++14", eLanguageTypeC_plus_plus_14},
191     {"fortran03", eLanguageTypeFortran03},
192     {"fortran08", eLanguageTypeFortran08},
193     // Vendor Extensions
194     {"mipsassem", eLanguageTypeMipsAssembler},
195     {"renderscript", eLanguageTypeExtRenderScript},
196     // Now synonyms, in arbitrary order
197     {"objc", eLanguageTypeObjC},
198     {"objc++", eLanguageTypeObjC_plus_plus},
199     {"pascal", eLanguageTypePascal83}};
200 
201 static uint32_t num_languages =
202     sizeof(language_names) / sizeof(struct language_name_pair);
203 
204 LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
205   for (const auto &L : language_names) {
206     if (string.equals_lower(L.name))
207       return static_cast<LanguageType>(L.type);
208   }
209 
210   return eLanguageTypeUnknown;
211 }
212 
213 const char *Language::GetNameForLanguageType(LanguageType language) {
214   if (language < num_languages)
215     return language_names[language].name;
216   else
217     return language_names[eLanguageTypeUnknown].name;
218 }
219 
220 void Language::PrintAllLanguages(Stream &s, const char *prefix,
221                                  const char *suffix) {
222   for (uint32_t i = 1; i < num_languages; i++) {
223     s.Printf("%s%s%s", prefix, language_names[i].name, suffix);
224   }
225 }
226 
227 void Language::ForAllLanguages(
228     std::function<bool(lldb::LanguageType)> callback) {
229   for (uint32_t i = 1; i < num_languages; i++) {
230     if (!callback(language_names[i].type))
231       break;
232   }
233 }
234 
235 bool Language::LanguageIsCPlusPlus(LanguageType language) {
236   switch (language) {
237   case eLanguageTypeC_plus_plus:
238   case eLanguageTypeC_plus_plus_03:
239   case eLanguageTypeC_plus_plus_11:
240   case eLanguageTypeC_plus_plus_14:
241   case eLanguageTypeObjC_plus_plus:
242     return true;
243   default:
244     return false;
245   }
246 }
247 
248 bool Language::LanguageIsObjC(LanguageType language) {
249   switch (language) {
250   case eLanguageTypeObjC:
251   case eLanguageTypeObjC_plus_plus:
252     return true;
253   default:
254     return false;
255   }
256 }
257 
258 bool Language::LanguageIsC(LanguageType language) {
259   switch (language) {
260   case eLanguageTypeC:
261   case eLanguageTypeC89:
262   case eLanguageTypeC99:
263   case eLanguageTypeC11:
264     return true;
265   default:
266     return false;
267   }
268 }
269 
270 bool Language::LanguageIsCFamily(LanguageType language) {
271   switch (language) {
272   case eLanguageTypeC:
273   case eLanguageTypeC89:
274   case eLanguageTypeC99:
275   case eLanguageTypeC11:
276   case eLanguageTypeC_plus_plus:
277   case eLanguageTypeC_plus_plus_03:
278   case eLanguageTypeC_plus_plus_11:
279   case eLanguageTypeC_plus_plus_14:
280   case eLanguageTypeObjC_plus_plus:
281   case eLanguageTypeObjC:
282     return true;
283   default:
284     return false;
285   }
286 }
287 
288 bool Language::LanguageIsPascal(LanguageType language) {
289   switch (language) {
290   case eLanguageTypePascal83:
291     return true;
292   default:
293     return false;
294   }
295 }
296 
297 LanguageType Language::GetPrimaryLanguage(LanguageType language) {
298   switch (language) {
299   case eLanguageTypeC_plus_plus:
300   case eLanguageTypeC_plus_plus_03:
301   case eLanguageTypeC_plus_plus_11:
302   case eLanguageTypeC_plus_plus_14:
303     return eLanguageTypeC_plus_plus;
304   case eLanguageTypeC:
305   case eLanguageTypeC89:
306   case eLanguageTypeC99:
307   case eLanguageTypeC11:
308     return eLanguageTypeC;
309   case eLanguageTypeObjC:
310   case eLanguageTypeObjC_plus_plus:
311     return eLanguageTypeObjC;
312   case eLanguageTypePascal83:
313   case eLanguageTypeCobol74:
314   case eLanguageTypeCobol85:
315   case eLanguageTypeFortran77:
316   case eLanguageTypeFortran90:
317   case eLanguageTypeFortran95:
318   case eLanguageTypeFortran03:
319   case eLanguageTypeFortran08:
320   case eLanguageTypeAda83:
321   case eLanguageTypeAda95:
322   case eLanguageTypeModula2:
323   case eLanguageTypeJava:
324   case eLanguageTypePLI:
325   case eLanguageTypeUPC:
326   case eLanguageTypeD:
327   case eLanguageTypePython:
328   case eLanguageTypeOpenCL:
329   case eLanguageTypeGo:
330   case eLanguageTypeModula3:
331   case eLanguageTypeHaskell:
332   case eLanguageTypeOCaml:
333   case eLanguageTypeRust:
334   case eLanguageTypeSwift:
335   case eLanguageTypeJulia:
336   case eLanguageTypeDylan:
337   case eLanguageTypeMipsAssembler:
338   case eLanguageTypeExtRenderScript:
339   case eLanguageTypeUnknown:
340   default:
341     return language;
342   }
343 }
344 
345 std::set<lldb::LanguageType> Language::GetSupportedLanguages() {
346   std::set<lldb::LanguageType> supported_languages;
347   ForEach([&](Language *lang) {
348     supported_languages.emplace(lang->GetLanguageType());
349     return true;
350   });
351   return supported_languages;
352 }
353 
354 LanguageSet Language::GetLanguagesSupportingTypeSystems() {
355   return PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
356 }
357 
358 LanguageSet Language::GetLanguagesSupportingTypeSystemsForExpressions() {
359   return PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions();
360 }
361 
362 LanguageSet Language::GetLanguagesSupportingREPLs() {
363   return PluginManager::GetREPLAllTypeSystemSupportedLanguages();
364 }
365 
366 std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
367   return nullptr;
368 }
369 
370 const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
371 
372 size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope,
373                                      const char *key, ResultSet &results,
374                                      bool append) {
375   if (!exe_scope || !exe_scope->CalculateTarget().get())
376     return false;
377 
378   if (!key || !key[0])
379     return false;
380 
381   if (!append)
382     results.clear();
383 
384   size_t old_size = results.size();
385 
386   if (this->Find_Impl(exe_scope, key, results))
387     return results.size() - old_size;
388   return 0;
389 }
390 
391 bool Language::ImageListTypeScavenger::Find_Impl(
392     ExecutionContextScope *exe_scope, const char *key, ResultSet &results) {
393   bool result = false;
394 
395   Target *target = exe_scope->CalculateTarget().get();
396   if (target) {
397     const auto &images(target->GetImages());
398     ConstString cs_key(key);
399     llvm::DenseSet<SymbolFile *> searched_sym_files;
400     TypeList matches;
401     images.FindTypes(nullptr, cs_key, false, UINT32_MAX, searched_sym_files,
402                      matches);
403     for (const auto &match : matches.Types()) {
404       if (match) {
405         CompilerType compiler_type(match->GetFullCompilerType());
406         compiler_type = AdjustForInclusion(compiler_type);
407         if (!compiler_type)
408           continue;
409         std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
410             new Result(compiler_type));
411         results.insert(std::move(scavengeresult));
412         result = true;
413       }
414     }
415   }
416 
417   return result;
418 }
419 
420 bool Language::GetFormatterPrefixSuffix(ValueObject &valobj,
421                                         ConstString type_hint,
422                                         std::string &prefix,
423                                         std::string &suffix) {
424   return false;
425 }
426 
427 DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
428   return nullptr;
429 }
430 
431 LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
432   return eLazyBoolCalculate;
433 }
434 
435 bool Language::IsNilReference(ValueObject &valobj) { return false; }
436 
437 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
438 
439 bool Language::GetFunctionDisplayName(const SymbolContext *sc,
440                                       const ExecutionContext *exe_ctx,
441                                       FunctionNameRepresentation representation,
442                                       Stream &s) {
443   return false;
444 }
445 
446 void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
447                                                Stream &s) {
448   GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
449 }
450 
451 void Language::GetDefaultExceptionResolverDescription(bool catch_on,
452                                                       bool throw_on,
453                                                       Stream &s) {
454   s.Printf("Exception breakpoint (catch: %s throw: %s)",
455            catch_on ? "on" : "off", throw_on ? "on" : "off");
456 }
457 // Constructor
458 Language::Language() {}
459 
460 // Destructor
461 Language::~Language() {}
462