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