1 | //===-- ClangModulesDeclVendor.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 "clang/Basic/Diagnostic.h" |
10 | #include "clang/Basic/DiagnosticFrontend.h" |
11 | #include "clang/Basic/TargetInfo.h" |
12 | #include "clang/Frontend/CompilerInstance.h" |
13 | #include "clang/Frontend/FrontendActions.h" |
14 | #include "clang/Frontend/TextDiagnosticPrinter.h" |
15 | #include "clang/Lex/Preprocessor.h" |
16 | #include "clang/Lex/PreprocessorOptions.h" |
17 | #include "clang/Parse/Parser.h" |
18 | #include "clang/Sema/Lookup.h" |
19 | #include "clang/Serialization/ASTReader.h" |
20 | #include "llvm/ADT/StringRef.h" |
21 | #include "llvm/Support/Path.h" |
22 | #include "llvm/Support/Threading.h" |
23 | |
24 | #include "ClangHost.h" |
25 | #include "ClangModulesDeclVendor.h" |
26 | |
27 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
28 | #include "lldb/Core/ModuleList.h" |
29 | #include "lldb/Core/Progress.h" |
30 | #include "lldb/Symbol/CompileUnit.h" |
31 | #include "lldb/Symbol/SourceModule.h" |
32 | #include "lldb/Target/Target.h" |
33 | #include "lldb/Utility/FileSpec.h" |
34 | #include "lldb/Utility/LLDBAssert.h" |
35 | #include "lldb/Utility/LLDBLog.h" |
36 | #include "lldb/Utility/Log.h" |
37 | |
38 | #include <memory> |
39 | |
40 | using namespace lldb_private; |
41 | |
42 | namespace { |
43 | /// Any Clang compiler requires a consumer for diagnostics. This one stores |
44 | /// them as strings so we can provide them to the user in case a module failed |
45 | /// to load. |
46 | class StoringDiagnosticConsumer : public clang::DiagnosticConsumer { |
47 | public: |
48 | StoringDiagnosticConsumer(); |
49 | |
50 | void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, |
51 | const clang::Diagnostic &info) override; |
52 | |
53 | void ClearDiagnostics(); |
54 | |
55 | void DumpDiagnostics(Stream &error_stream); |
56 | |
57 | void BeginSourceFile(const clang::LangOptions &LangOpts, |
58 | const clang::Preprocessor *PP = nullptr) override; |
59 | void EndSourceFile() override; |
60 | |
61 | private: |
62 | bool HandleModuleRemark(const clang::Diagnostic &info); |
63 | void SetCurrentModuleProgress(std::string module_name); |
64 | |
65 | typedef std::pair<clang::DiagnosticsEngine::Level, std::string> |
66 | IDAndDiagnostic; |
67 | std::vector<IDAndDiagnostic> m_diagnostics; |
68 | /// The DiagnosticPrinter used for creating the full diagnostic messages |
69 | /// that are stored in m_diagnostics. |
70 | std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer; |
71 | /// Output stream of m_diag_printer. |
72 | std::unique_ptr<llvm::raw_string_ostream> m_os; |
73 | /// Output string filled by m_os. Will be reused for different diagnostics. |
74 | std::string m_output; |
75 | /// A Progress with explicitly managed lifetime. |
76 | std::unique_ptr<Progress> m_current_progress_up; |
77 | std::vector<std::string> m_module_build_stack; |
78 | }; |
79 | |
80 | /// The private implementation of our ClangModulesDeclVendor. Contains all the |
81 | /// Clang state required to load modules. |
82 | class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor { |
83 | public: |
84 | ClangModulesDeclVendorImpl( |
85 | llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine, |
86 | std::shared_ptr<clang::CompilerInvocation> compiler_invocation, |
87 | std::unique_ptr<clang::CompilerInstance> compiler_instance, |
88 | std::unique_ptr<clang::Parser> parser); |
89 | |
90 | ~ClangModulesDeclVendorImpl() override = default; |
91 | |
92 | bool AddModule(const SourceModule &module, ModuleVector *exported_modules, |
93 | Stream &error_stream) override; |
94 | |
95 | bool AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules, |
96 | Stream &error_stream) override; |
97 | |
98 | uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, |
99 | std::vector<CompilerDecl> &decls) override; |
100 | |
101 | void ForEachMacro( |
102 | const ModuleVector &modules, |
103 | std::function<bool(llvm::StringRef, llvm::StringRef)> handler) override; |
104 | |
105 | private: |
106 | typedef llvm::DenseSet<ModuleID> ExportedModuleSet; |
107 | void ReportModuleExportsHelper(ExportedModuleSet &exports, |
108 | clang::Module *module); |
109 | |
110 | void ReportModuleExports(ModuleVector &exports, clang::Module *module); |
111 | |
112 | clang::ModuleLoadResult DoGetModule(clang::ModuleIdPath path, |
113 | bool make_visible); |
114 | |
115 | bool m_enabled = false; |
116 | |
117 | llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine; |
118 | std::shared_ptr<clang::CompilerInvocation> m_compiler_invocation; |
119 | std::unique_ptr<clang::CompilerInstance> m_compiler_instance; |
120 | std::unique_ptr<clang::Parser> m_parser; |
121 | size_t m_source_location_index = |
122 | 0; // used to give name components fake SourceLocations |
123 | |
124 | typedef std::vector<ConstString> ImportedModule; |
125 | typedef std::map<ImportedModule, clang::Module *> ImportedModuleMap; |
126 | typedef llvm::DenseSet<ModuleID> ImportedModuleSet; |
127 | ImportedModuleMap m_imported_modules; |
128 | ImportedModuleSet m_user_imported_modules; |
129 | // We assume that every ASTContext has an TypeSystemClang, so we also store |
130 | // a custom TypeSystemClang for our internal ASTContext. |
131 | std::shared_ptr<TypeSystemClang> m_ast_context; |
132 | }; |
133 | } // anonymous namespace |
134 | |
135 | StoringDiagnosticConsumer::StoringDiagnosticConsumer() { |
136 | auto *options = new clang::DiagnosticOptions(); |
137 | m_os = std::make_unique<llvm::raw_string_ostream>(args&: m_output); |
138 | m_diag_printer = |
139 | std::make_unique<clang::TextDiagnosticPrinter>(args&: *m_os, args&: options); |
140 | } |
141 | |
142 | void StoringDiagnosticConsumer::HandleDiagnostic( |
143 | clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) { |
144 | if (HandleModuleRemark(info)) |
145 | return; |
146 | |
147 | // Print the diagnostic to m_output. |
148 | m_output.clear(); |
149 | m_diag_printer->HandleDiagnostic(Level: DiagLevel, Info: info); |
150 | m_os->flush(); |
151 | |
152 | // Store the diagnostic for later. |
153 | m_diagnostics.push_back(x: IDAndDiagnostic(DiagLevel, m_output)); |
154 | } |
155 | |
156 | void StoringDiagnosticConsumer::ClearDiagnostics() { m_diagnostics.clear(); } |
157 | |
158 | void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) { |
159 | for (IDAndDiagnostic &diag : m_diagnostics) { |
160 | switch (diag.first) { |
161 | default: |
162 | error_stream.PutCString(cstr: diag.second); |
163 | error_stream.PutChar(ch: '\n'); |
164 | break; |
165 | case clang::DiagnosticsEngine::Level::Ignored: |
166 | break; |
167 | } |
168 | } |
169 | } |
170 | |
171 | void StoringDiagnosticConsumer::BeginSourceFile( |
172 | const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) { |
173 | m_diag_printer->BeginSourceFile(LO: LangOpts, PP); |
174 | } |
175 | |
176 | void StoringDiagnosticConsumer::EndSourceFile() { |
177 | m_current_progress_up = nullptr; |
178 | m_diag_printer->EndSourceFile(); |
179 | } |
180 | |
181 | bool StoringDiagnosticConsumer::HandleModuleRemark( |
182 | const clang::Diagnostic &info) { |
183 | Log *log = GetLog(mask: LLDBLog::Types | LLDBLog::Expressions); |
184 | switch (info.getID()) { |
185 | case clang::diag::remark_module_build: { |
186 | const auto &module_name = info.getArgStdStr(Idx: 0); |
187 | SetCurrentModuleProgress(module_name); |
188 | m_module_build_stack.push_back(x: module_name); |
189 | |
190 | const auto &module_path = info.getArgStdStr(Idx: 1); |
191 | LLDB_LOG(log, "Building Clang module {0} as {1}" , module_name, module_path); |
192 | return true; |
193 | } |
194 | case clang::diag::remark_module_build_done: { |
195 | // The current module is done. |
196 | m_module_build_stack.pop_back(); |
197 | if (m_module_build_stack.empty()) { |
198 | m_current_progress_up = nullptr; |
199 | } else { |
200 | // When the just completed module began building, a module that depends on |
201 | // it ("module A") was effectively paused. Update the progress to re-show |
202 | // "module A" as continuing to be built. |
203 | const auto &resumed_module_name = m_module_build_stack.back(); |
204 | SetCurrentModuleProgress(resumed_module_name); |
205 | } |
206 | |
207 | const auto &module_name = info.getArgStdStr(Idx: 0); |
208 | LLDB_LOG(log, "Finished building Clang module {0}" , module_name); |
209 | return true; |
210 | } |
211 | default: |
212 | return false; |
213 | } |
214 | } |
215 | |
216 | void StoringDiagnosticConsumer::SetCurrentModuleProgress( |
217 | std::string module_name) { |
218 | if (!m_current_progress_up) |
219 | m_current_progress_up = |
220 | std::make_unique<Progress>(args: "Building Clang modules" ); |
221 | |
222 | m_current_progress_up->Increment(amount: 1, updated_detail: std::move(module_name)); |
223 | } |
224 | |
225 | ClangModulesDeclVendor::ClangModulesDeclVendor() |
226 | : ClangDeclVendor(eClangModuleDeclVendor) {} |
227 | |
228 | ClangModulesDeclVendor::~ClangModulesDeclVendor() = default; |
229 | |
230 | ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl( |
231 | llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine, |
232 | std::shared_ptr<clang::CompilerInvocation> compiler_invocation, |
233 | std::unique_ptr<clang::CompilerInstance> compiler_instance, |
234 | std::unique_ptr<clang::Parser> parser) |
235 | : m_diagnostics_engine(std::move(diagnostics_engine)), |
236 | m_compiler_invocation(std::move(compiler_invocation)), |
237 | m_compiler_instance(std::move(compiler_instance)), |
238 | m_parser(std::move(parser)) { |
239 | |
240 | // Initialize our TypeSystemClang. |
241 | m_ast_context = |
242 | std::make_shared<TypeSystemClang>(args: "ClangModulesDeclVendor ASTContext" , |
243 | args&: m_compiler_instance->getASTContext()); |
244 | } |
245 | |
246 | void ClangModulesDeclVendorImpl::ReportModuleExportsHelper( |
247 | ExportedModuleSet &exports, clang::Module *module) { |
248 | if (exports.count(V: reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module))) |
249 | return; |
250 | |
251 | exports.insert(V: reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module)); |
252 | |
253 | llvm::SmallVector<clang::Module *, 2> sub_exports; |
254 | |
255 | module->getExportedModules(Exported&: sub_exports); |
256 | |
257 | for (clang::Module *module : sub_exports) |
258 | ReportModuleExportsHelper(exports, module); |
259 | } |
260 | |
261 | void ClangModulesDeclVendorImpl::ReportModuleExports( |
262 | ClangModulesDeclVendor::ModuleVector &exports, clang::Module *module) { |
263 | ExportedModuleSet exports_set; |
264 | |
265 | ReportModuleExportsHelper(exports&: exports_set, module); |
266 | |
267 | for (ModuleID module : exports_set) |
268 | exports.push_back(x: module); |
269 | } |
270 | |
271 | bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, |
272 | ModuleVector *exported_modules, |
273 | Stream &error_stream) { |
274 | // Fail early. |
275 | |
276 | if (m_compiler_instance->hadModuleLoaderFatalFailure()) { |
277 | error_stream.PutCString(cstr: "error: Couldn't load a module because the module " |
278 | "loader is in a fatal state.\n" ); |
279 | return false; |
280 | } |
281 | |
282 | // Check if we've already imported this module. |
283 | |
284 | std::vector<ConstString> imported_module; |
285 | |
286 | for (ConstString path_component : module.path) |
287 | imported_module.push_back(x: path_component); |
288 | |
289 | { |
290 | ImportedModuleMap::iterator mi = m_imported_modules.find(x: imported_module); |
291 | |
292 | if (mi != m_imported_modules.end()) { |
293 | if (exported_modules) |
294 | ReportModuleExports(exports&: *exported_modules, module: mi->second); |
295 | return true; |
296 | } |
297 | } |
298 | |
299 | clang::HeaderSearch &HS = |
300 | m_compiler_instance->getPreprocessor().getHeaderSearchInfo(); |
301 | |
302 | if (module.search_path) { |
303 | auto path_begin = llvm::sys::path::begin(path: module.search_path.GetStringRef()); |
304 | auto path_end = llvm::sys::path::end(path: module.search_path.GetStringRef()); |
305 | auto sysroot_begin = llvm::sys::path::begin(path: module.sysroot.GetStringRef()); |
306 | auto sysroot_end = llvm::sys::path::end(path: module.sysroot.GetStringRef()); |
307 | // FIXME: Use C++14 std::equal(it, it, it, it) variant once it's available. |
308 | bool is_system_module = (std::distance(first: path_begin, last: path_end) >= |
309 | std::distance(first: sysroot_begin, last: sysroot_end)) && |
310 | std::equal(first1: sysroot_begin, last1: sysroot_end, first2: path_begin); |
311 | // No need to inject search paths to modules in the sysroot. |
312 | if (!is_system_module) { |
313 | auto error = [&]() { |
314 | error_stream.Printf(format: "error: No module map file in %s\n" , |
315 | module.search_path.AsCString()); |
316 | return false; |
317 | }; |
318 | |
319 | bool is_system = true; |
320 | bool is_framework = false; |
321 | auto dir = HS.getFileMgr().getOptionalDirectoryRef( |
322 | DirName: module.search_path.GetStringRef()); |
323 | if (!dir) |
324 | return error(); |
325 | auto file = HS.lookupModuleMapFile(Dir: *dir, IsFramework: is_framework); |
326 | if (!file) |
327 | return error(); |
328 | if (!HS.loadModuleMapFile(File: *file, IsSystem: is_system)) |
329 | return error(); |
330 | } |
331 | } |
332 | if (!HS.lookupModule(ModuleName: module.path.front().GetStringRef())) { |
333 | error_stream.Printf(format: "error: Header search couldn't locate module %s\n" , |
334 | module.path.front().AsCString()); |
335 | return false; |
336 | } |
337 | |
338 | llvm::SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>, |
339 | 4> |
340 | clang_path; |
341 | |
342 | { |
343 | clang::SourceManager &source_manager = |
344 | m_compiler_instance->getASTContext().getSourceManager(); |
345 | |
346 | for (ConstString path_component : module.path) { |
347 | clang_path.push_back(Elt: std::make_pair( |
348 | x: &m_compiler_instance->getASTContext().Idents.get( |
349 | Name: path_component.GetStringRef()), |
350 | y: source_manager.getLocForStartOfFile(FID: source_manager.getMainFileID()) |
351 | .getLocWithOffset(Offset: m_source_location_index++))); |
352 | } |
353 | } |
354 | |
355 | StoringDiagnosticConsumer *diagnostic_consumer = |
356 | static_cast<StoringDiagnosticConsumer *>( |
357 | m_compiler_instance->getDiagnostics().getClient()); |
358 | |
359 | diagnostic_consumer->ClearDiagnostics(); |
360 | |
361 | clang::Module *top_level_module = DoGetModule(path: clang_path.front(), make_visible: false); |
362 | |
363 | if (!top_level_module) { |
364 | diagnostic_consumer->DumpDiagnostics(error_stream); |
365 | error_stream.Printf(format: "error: Couldn't load top-level module %s\n" , |
366 | module.path.front().AsCString()); |
367 | return false; |
368 | } |
369 | |
370 | clang::Module *submodule = top_level_module; |
371 | |
372 | for (auto &component : llvm::ArrayRef<ConstString>(module.path).drop_front()) { |
373 | submodule = submodule->findSubmodule(Name: component.GetStringRef()); |
374 | if (!submodule) { |
375 | diagnostic_consumer->DumpDiagnostics(error_stream); |
376 | error_stream.Printf(format: "error: Couldn't load submodule %s\n" , |
377 | component.GetCString()); |
378 | return false; |
379 | } |
380 | } |
381 | |
382 | clang::Module *requested_module = DoGetModule(path: clang_path, make_visible: true); |
383 | |
384 | if (requested_module != nullptr) { |
385 | if (exported_modules) |
386 | ReportModuleExports(exports&: *exported_modules, module: requested_module); |
387 | |
388 | m_imported_modules[imported_module] = requested_module; |
389 | |
390 | m_enabled = true; |
391 | |
392 | return true; |
393 | } |
394 | |
395 | return false; |
396 | } |
397 | |
398 | bool ClangModulesDeclVendor::LanguageSupportsClangModules( |
399 | lldb::LanguageType language) { |
400 | switch (language) { |
401 | default: |
402 | return false; |
403 | case lldb::LanguageType::eLanguageTypeC: |
404 | case lldb::LanguageType::eLanguageTypeC11: |
405 | case lldb::LanguageType::eLanguageTypeC89: |
406 | case lldb::LanguageType::eLanguageTypeC99: |
407 | case lldb::LanguageType::eLanguageTypeC_plus_plus: |
408 | case lldb::LanguageType::eLanguageTypeC_plus_plus_03: |
409 | case lldb::LanguageType::eLanguageTypeC_plus_plus_11: |
410 | case lldb::LanguageType::eLanguageTypeC_plus_plus_14: |
411 | case lldb::LanguageType::eLanguageTypeObjC: |
412 | case lldb::LanguageType::eLanguageTypeObjC_plus_plus: |
413 | return true; |
414 | } |
415 | } |
416 | |
417 | bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit( |
418 | CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules, |
419 | Stream &error_stream) { |
420 | if (LanguageSupportsClangModules(language: cu.GetLanguage())) { |
421 | for (auto &imported_module : cu.GetImportedModules()) |
422 | if (!AddModule(module: imported_module, exported_modules: &exported_modules, error_stream)) |
423 | return false; |
424 | } |
425 | return true; |
426 | } |
427 | |
428 | // ClangImporter::lookupValue |
429 | |
430 | uint32_t |
431 | ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, |
432 | uint32_t max_matches, |
433 | std::vector<CompilerDecl> &decls) { |
434 | if (!m_enabled) |
435 | return 0; |
436 | |
437 | if (!append) |
438 | decls.clear(); |
439 | |
440 | clang::IdentifierInfo &ident = |
441 | m_compiler_instance->getASTContext().Idents.get(Name: name.GetStringRef()); |
442 | |
443 | clang::LookupResult lookup_result( |
444 | m_compiler_instance->getSema(), clang::DeclarationName(&ident), |
445 | clang::SourceLocation(), clang::Sema::LookupOrdinaryName); |
446 | |
447 | m_compiler_instance->getSema().LookupName( |
448 | R&: lookup_result, |
449 | S: m_compiler_instance->getSema().getScopeForContext( |
450 | m_compiler_instance->getASTContext().getTranslationUnitDecl())); |
451 | |
452 | uint32_t num_matches = 0; |
453 | |
454 | for (clang::NamedDecl *named_decl : lookup_result) { |
455 | if (num_matches >= max_matches) |
456 | return num_matches; |
457 | |
458 | decls.push_back(x: m_ast_context->GetCompilerDecl(named_decl)); |
459 | ++num_matches; |
460 | } |
461 | |
462 | return num_matches; |
463 | } |
464 | |
465 | void ClangModulesDeclVendorImpl::ForEachMacro( |
466 | const ClangModulesDeclVendor::ModuleVector &modules, |
467 | std::function<bool(llvm::StringRef, llvm::StringRef)> handler) { |
468 | if (!m_enabled) |
469 | return; |
470 | |
471 | typedef std::map<ModuleID, ssize_t> ModulePriorityMap; |
472 | ModulePriorityMap module_priorities; |
473 | |
474 | ssize_t priority = 0; |
475 | |
476 | for (ModuleID module : modules) |
477 | module_priorities[module] = priority++; |
478 | |
479 | if (m_compiler_instance->getPreprocessor().getExternalSource()) { |
480 | m_compiler_instance->getPreprocessor() |
481 | .getExternalSource() |
482 | ->ReadDefinedMacros(); |
483 | } |
484 | |
485 | for (clang::Preprocessor::macro_iterator |
486 | mi = m_compiler_instance->getPreprocessor().macro_begin(), |
487 | me = m_compiler_instance->getPreprocessor().macro_end(); |
488 | mi != me; ++mi) { |
489 | const clang::IdentifierInfo *ii = nullptr; |
490 | |
491 | { |
492 | if (clang::IdentifierInfoLookup *lookup = |
493 | m_compiler_instance->getPreprocessor() |
494 | .getIdentifierTable() |
495 | .getExternalIdentifierLookup()) { |
496 | lookup->get(Name: mi->first->getName()); |
497 | } |
498 | if (!ii) |
499 | ii = mi->first; |
500 | } |
501 | |
502 | ssize_t found_priority = -1; |
503 | clang::MacroInfo *macro_info = nullptr; |
504 | |
505 | for (clang::ModuleMacro *module_macro : |
506 | m_compiler_instance->getPreprocessor().getLeafModuleMacros(II: ii)) { |
507 | clang::Module *module = module_macro->getOwningModule(); |
508 | |
509 | { |
510 | ModulePriorityMap::iterator pi = |
511 | module_priorities.find(x: reinterpret_cast<ModuleID>(module)); |
512 | |
513 | if (pi != module_priorities.end() && pi->second > found_priority) { |
514 | macro_info = module_macro->getMacroInfo(); |
515 | found_priority = pi->second; |
516 | } |
517 | } |
518 | |
519 | clang::Module *top_level_module = module->getTopLevelModule(); |
520 | |
521 | if (top_level_module != module) { |
522 | ModulePriorityMap::iterator pi = module_priorities.find( |
523 | x: reinterpret_cast<ModuleID>(top_level_module)); |
524 | |
525 | if ((pi != module_priorities.end()) && pi->second > found_priority) { |
526 | macro_info = module_macro->getMacroInfo(); |
527 | found_priority = pi->second; |
528 | } |
529 | } |
530 | } |
531 | |
532 | if (macro_info) { |
533 | std::string macro_expansion = "#define " ; |
534 | llvm::StringRef macro_identifier = mi->first->getName(); |
535 | macro_expansion.append(str: macro_identifier.str()); |
536 | |
537 | { |
538 | if (macro_info->isFunctionLike()) { |
539 | macro_expansion.append(s: "(" ); |
540 | |
541 | bool first_arg = true; |
542 | |
543 | for (auto pi = macro_info->param_begin(), |
544 | pe = macro_info->param_end(); |
545 | pi != pe; ++pi) { |
546 | if (!first_arg) |
547 | macro_expansion.append(s: ", " ); |
548 | else |
549 | first_arg = false; |
550 | |
551 | macro_expansion.append(str: (*pi)->getName().str()); |
552 | } |
553 | |
554 | if (macro_info->isC99Varargs()) { |
555 | if (first_arg) |
556 | macro_expansion.append(s: "..." ); |
557 | else |
558 | macro_expansion.append(s: ", ..." ); |
559 | } else if (macro_info->isGNUVarargs()) |
560 | macro_expansion.append(s: "..." ); |
561 | |
562 | macro_expansion.append(s: ")" ); |
563 | } |
564 | |
565 | macro_expansion.append(s: " " ); |
566 | |
567 | bool first_token = true; |
568 | |
569 | for (clang::MacroInfo::const_tokens_iterator |
570 | ti = macro_info->tokens_begin(), |
571 | te = macro_info->tokens_end(); |
572 | ti != te; ++ti) { |
573 | if (!first_token) |
574 | macro_expansion.append(s: " " ); |
575 | else |
576 | first_token = false; |
577 | |
578 | if (ti->isLiteral()) { |
579 | if (const char *literal_data = ti->getLiteralData()) { |
580 | std::string token_str(literal_data, ti->getLength()); |
581 | macro_expansion.append(str: token_str); |
582 | } else { |
583 | bool invalid = false; |
584 | const char *literal_source = |
585 | m_compiler_instance->getSourceManager().getCharacterData( |
586 | SL: ti->getLocation(), Invalid: &invalid); |
587 | |
588 | if (invalid) { |
589 | lldbassert(0 && "Unhandled token kind" ); |
590 | macro_expansion.append(s: "<unknown literal value>" ); |
591 | } else { |
592 | macro_expansion.append( |
593 | str: std::string(literal_source, ti->getLength())); |
594 | } |
595 | } |
596 | } else if (const char *punctuator_spelling = |
597 | clang::tok::getPunctuatorSpelling(Kind: ti->getKind())) { |
598 | macro_expansion.append(s: punctuator_spelling); |
599 | } else if (const char *keyword_spelling = |
600 | clang::tok::getKeywordSpelling(Kind: ti->getKind())) { |
601 | macro_expansion.append(s: keyword_spelling); |
602 | } else { |
603 | switch (ti->getKind()) { |
604 | case clang::tok::TokenKind::identifier: |
605 | macro_expansion.append(str: ti->getIdentifierInfo()->getName().str()); |
606 | break; |
607 | case clang::tok::TokenKind::raw_identifier: |
608 | macro_expansion.append(str: ti->getRawIdentifier().str()); |
609 | break; |
610 | default: |
611 | macro_expansion.append(s: ti->getName()); |
612 | break; |
613 | } |
614 | } |
615 | } |
616 | |
617 | if (handler(macro_identifier, macro_expansion)) { |
618 | return; |
619 | } |
620 | } |
621 | } |
622 | } |
623 | } |
624 | |
625 | clang::ModuleLoadResult |
626 | ClangModulesDeclVendorImpl::DoGetModule(clang::ModuleIdPath path, |
627 | bool make_visible) { |
628 | clang::Module::NameVisibilityKind visibility = |
629 | make_visible ? clang::Module::AllVisible : clang::Module::Hidden; |
630 | |
631 | const bool is_inclusion_directive = false; |
632 | |
633 | return m_compiler_instance->loadModule(ImportLoc: path.front().second, Path: path, Visibility: visibility, |
634 | IsInclusionDirective: is_inclusion_directive); |
635 | } |
636 | |
637 | static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer" ; |
638 | |
639 | lldb_private::ClangModulesDeclVendor * |
640 | ClangModulesDeclVendor::Create(Target &target) { |
641 | // FIXME we should insure programmatically that the expression parser's |
642 | // compiler and the modules runtime's |
643 | // compiler are both initialized in the same way – preferably by the same |
644 | // code. |
645 | |
646 | if (!target.GetPlatform()->SupportsModules()) |
647 | return nullptr; |
648 | |
649 | const ArchSpec &arch = target.GetArchitecture(); |
650 | |
651 | std::vector<std::string> compiler_invocation_arguments = { |
652 | "clang" , |
653 | "-fmodules" , |
654 | "-fimplicit-module-maps" , |
655 | "-fcxx-modules" , |
656 | "-fsyntax-only" , |
657 | "-femit-all-decls" , |
658 | "-target" , |
659 | arch.GetTriple().str(), |
660 | "-fmodules-validate-system-headers" , |
661 | "-Werror=non-modular-include-in-framework-module" , |
662 | "-Xclang=-fincremental-extensions" , |
663 | "-Rmodule-build" }; |
664 | |
665 | target.GetPlatform()->AddClangModuleCompilationOptions( |
666 | target: &target, options&: compiler_invocation_arguments); |
667 | |
668 | compiler_invocation_arguments.push_back(x: ModuleImportBufferName); |
669 | |
670 | // Add additional search paths with { "-I", path } or { "-F", path } here. |
671 | |
672 | { |
673 | llvm::SmallString<128> path; |
674 | const auto &props = ModuleList::GetGlobalModuleListProperties(); |
675 | props.GetClangModulesCachePath().GetPath(path); |
676 | std::string module_cache_argument("-fmodules-cache-path=" ); |
677 | module_cache_argument.append(str: std::string(path.str())); |
678 | compiler_invocation_arguments.push_back(x: module_cache_argument); |
679 | } |
680 | |
681 | FileSpecList module_search_paths = target.GetClangModuleSearchPaths(); |
682 | |
683 | for (size_t spi = 0, spe = module_search_paths.GetSize(); spi < spe; ++spi) { |
684 | const FileSpec &search_path = module_search_paths.GetFileSpecAtIndex(idx: spi); |
685 | |
686 | std::string search_path_argument = "-I" ; |
687 | search_path_argument.append(str: search_path.GetPath()); |
688 | |
689 | compiler_invocation_arguments.push_back(x: search_path_argument); |
690 | } |
691 | |
692 | { |
693 | FileSpec clang_resource_dir = GetClangResourceDir(); |
694 | |
695 | if (FileSystem::Instance().IsDirectory(path: clang_resource_dir.GetPath())) { |
696 | compiler_invocation_arguments.push_back(x: "-resource-dir" ); |
697 | compiler_invocation_arguments.push_back(x: clang_resource_dir.GetPath()); |
698 | } |
699 | } |
700 | |
701 | std::vector<const char *> compiler_invocation_argument_cstrs; |
702 | compiler_invocation_argument_cstrs.reserve( |
703 | n: compiler_invocation_arguments.size()); |
704 | for (const std::string &arg : compiler_invocation_arguments) |
705 | compiler_invocation_argument_cstrs.push_back(x: arg.c_str()); |
706 | |
707 | auto diag_options_up = |
708 | clang::CreateAndPopulateDiagOpts(Argv: compiler_invocation_argument_cstrs); |
709 | llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine = |
710 | clang::CompilerInstance::createDiagnostics(Opts: diag_options_up.release(), |
711 | Client: new StoringDiagnosticConsumer); |
712 | |
713 | Log *log = GetLog(mask: LLDBLog::Expressions); |
714 | LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}" , |
715 | llvm::make_range(compiler_invocation_arguments.begin(), |
716 | compiler_invocation_arguments.end())); |
717 | |
718 | clang::CreateInvocationOptions CIOpts; |
719 | CIOpts.Diags = diagnostics_engine; |
720 | std::shared_ptr<clang::CompilerInvocation> invocation = |
721 | clang::createInvocation(Args: compiler_invocation_argument_cstrs, |
722 | Opts: std::move(CIOpts)); |
723 | |
724 | if (!invocation) |
725 | return nullptr; |
726 | |
727 | std::unique_ptr<llvm::MemoryBuffer> source_buffer = |
728 | llvm::MemoryBuffer::getMemBuffer( |
729 | InputData: "extern int __lldb __attribute__((unavailable));" , |
730 | BufferName: ModuleImportBufferName); |
731 | |
732 | invocation->getPreprocessorOpts().addRemappedFile(From: ModuleImportBufferName, |
733 | To: source_buffer.release()); |
734 | |
735 | std::unique_ptr<clang::CompilerInstance> instance( |
736 | new clang::CompilerInstance); |
737 | |
738 | // Make sure clang uses the same VFS as LLDB. |
739 | instance->createFileManager(VFS: FileSystem::Instance().GetVirtualFileSystem()); |
740 | instance->setDiagnostics(diagnostics_engine.get()); |
741 | instance->setInvocation(invocation); |
742 | |
743 | std::unique_ptr<clang::FrontendAction> action(new clang::SyntaxOnlyAction); |
744 | |
745 | instance->setTarget(clang::TargetInfo::CreateTargetInfo( |
746 | Diags&: *diagnostics_engine, Opts: instance->getInvocation().TargetOpts)); |
747 | |
748 | if (!instance->hasTarget()) |
749 | return nullptr; |
750 | |
751 | instance->getTarget().adjust(Diags&: *diagnostics_engine, Opts&: instance->getLangOpts()); |
752 | |
753 | if (!action->BeginSourceFile(CI&: *instance, |
754 | Input: instance->getFrontendOpts().Inputs[0])) |
755 | return nullptr; |
756 | |
757 | instance->createASTReader(); |
758 | |
759 | instance->createSema(TUKind: action->getTranslationUnitKind(), CompletionConsumer: nullptr); |
760 | |
761 | const bool skipFunctionBodies = false; |
762 | std::unique_ptr<clang::Parser> parser(new clang::Parser( |
763 | instance->getPreprocessor(), instance->getSema(), skipFunctionBodies)); |
764 | |
765 | instance->getPreprocessor().EnterMainSourceFile(); |
766 | parser->Initialize(); |
767 | |
768 | clang::Parser::DeclGroupPtrTy parsed; |
769 | auto ImportState = clang::Sema::ModuleImportState::NotACXX20Module; |
770 | while (!parser->ParseTopLevelDecl(Result&: parsed, ImportState)) |
771 | ; |
772 | |
773 | return new ClangModulesDeclVendorImpl(std::move(diagnostics_engine), |
774 | std::move(invocation), |
775 | std::move(instance), std::move(parser)); |
776 | } |
777 | |