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
40using namespace lldb_private;
41
42namespace {
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.
46class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
47public:
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
61private:
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.
82class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
83public:
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
105private:
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
135StoringDiagnosticConsumer::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
142void 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
156void StoringDiagnosticConsumer::ClearDiagnostics() { m_diagnostics.clear(); }
157
158void 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
171void StoringDiagnosticConsumer::BeginSourceFile(
172 const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) {
173 m_diag_printer->BeginSourceFile(LO: LangOpts, PP);
174}
175
176void StoringDiagnosticConsumer::EndSourceFile() {
177 m_current_progress_up = nullptr;
178 m_diag_printer->EndSourceFile();
179}
180
181bool 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
216void 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
225ClangModulesDeclVendor::ClangModulesDeclVendor()
226 : ClangDeclVendor(eClangModuleDeclVendor) {}
227
228ClangModulesDeclVendor::~ClangModulesDeclVendor() = default;
229
230ClangModulesDeclVendorImpl::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
246void 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
261void 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
271bool 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
398bool 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
417bool 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
430uint32_t
431ClangModulesDeclVendorImpl::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
465void 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
625clang::ModuleLoadResult
626ClangModulesDeclVendorImpl::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
637static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer";
638
639lldb_private::ClangModulesDeclVendor *
640ClangModulesDeclVendor::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

source code of lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp