xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
StoringDiagnosticConsumer()135 StoringDiagnosticConsumer::StoringDiagnosticConsumer() {
136   auto *options = new clang::DiagnosticOptions();
137   m_os = std::make_unique<llvm::raw_string_ostream>(m_output);
138   m_diag_printer =
139       std::make_unique<clang::TextDiagnosticPrinter>(*m_os, options);
140 }
141 
HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel,const clang::Diagnostic & info)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(DiagLevel, info);
150   m_os->flush();
151 
152   // Store the diagnostic for later.
153   m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, m_output));
154 }
155 
ClearDiagnostics()156 void StoringDiagnosticConsumer::ClearDiagnostics() { m_diagnostics.clear(); }
157 
DumpDiagnostics(Stream & error_stream)158 void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) {
159   for (IDAndDiagnostic &diag : m_diagnostics) {
160     switch (diag.first) {
161     default:
162       error_stream.PutCString(diag.second);
163       error_stream.PutChar('\n');
164       break;
165     case clang::DiagnosticsEngine::Level::Ignored:
166       break;
167     }
168   }
169 }
170 
BeginSourceFile(const clang::LangOptions & LangOpts,const clang::Preprocessor * PP)171 void StoringDiagnosticConsumer::BeginSourceFile(
172     const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) {
173   m_diag_printer->BeginSourceFile(LangOpts, PP);
174 }
175 
EndSourceFile()176 void StoringDiagnosticConsumer::EndSourceFile() {
177   m_current_progress_up = nullptr;
178   m_diag_printer->EndSourceFile();
179 }
180 
HandleModuleRemark(const clang::Diagnostic & info)181 bool StoringDiagnosticConsumer::HandleModuleRemark(
182     const clang::Diagnostic &info) {
183   Log *log = GetLog(LLDBLog::Types | LLDBLog::Expressions);
184   switch (info.getID()) {
185   case clang::diag::remark_module_build: {
186     const auto &module_name = info.getArgStdStr(0);
187     SetCurrentModuleProgress(module_name);
188     m_module_build_stack.push_back(module_name);
189 
190     const auto &module_path = info.getArgStdStr(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(0);
208     LLDB_LOG(log, "Finished building Clang module {0}", module_name);
209     return true;
210   }
211   default:
212     return false;
213   }
214 }
215 
SetCurrentModuleProgress(std::string module_name)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>("Building Clang modules");
221 
222   m_current_progress_up->Increment(1, std::move(module_name));
223 }
224 
ClangModulesDeclVendor()225 ClangModulesDeclVendor::ClangModulesDeclVendor()
226     : ClangDeclVendor(eClangModuleDeclVendor) {}
227 
228 ClangModulesDeclVendor::~ClangModulesDeclVendor() = default;
229 
ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,std::shared_ptr<clang::CompilerInvocation> compiler_invocation,std::unique_ptr<clang::CompilerInstance> compiler_instance,std::unique_ptr<clang::Parser> parser)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>("ClangModulesDeclVendor ASTContext",
243                                         m_compiler_instance->getASTContext());
244 }
245 
ReportModuleExportsHelper(ExportedModuleSet & exports,clang::Module * module)246 void ClangModulesDeclVendorImpl::ReportModuleExportsHelper(
247     ExportedModuleSet &exports, clang::Module *module) {
248   if (exports.count(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module)))
249     return;
250 
251   exports.insert(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module));
252 
253   llvm::SmallVector<clang::Module *, 2> sub_exports;
254 
255   module->getExportedModules(sub_exports);
256 
257   for (clang::Module *module : sub_exports)
258     ReportModuleExportsHelper(exports, module);
259 }
260 
ReportModuleExports(ClangModulesDeclVendor::ModuleVector & exports,clang::Module * module)261 void ClangModulesDeclVendorImpl::ReportModuleExports(
262     ClangModulesDeclVendor::ModuleVector &exports, clang::Module *module) {
263   ExportedModuleSet exports_set;
264 
265   ReportModuleExportsHelper(exports_set, module);
266 
267   for (ModuleID module : exports_set)
268     exports.push_back(module);
269 }
270 
AddModule(const SourceModule & module,ModuleVector * exported_modules,Stream & error_stream)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("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(path_component);
288 
289   {
290     ImportedModuleMap::iterator mi = m_imported_modules.find(imported_module);
291 
292     if (mi != m_imported_modules.end()) {
293       if (exported_modules)
294         ReportModuleExports(*exported_modules, 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(module.search_path.GetStringRef());
304     auto path_end = llvm::sys::path::end(module.search_path.GetStringRef());
305     auto sysroot_begin = llvm::sys::path::begin(module.sysroot.GetStringRef());
306     auto sysroot_end = llvm::sys::path::end(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(path_begin, path_end) >=
309                              std::distance(sysroot_begin, sysroot_end)) &&
310                             std::equal(sysroot_begin, sysroot_end, 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("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           module.search_path.GetStringRef());
323       if (!dir)
324         return error();
325       auto file = HS.lookupModuleMapFile(*dir, is_framework);
326       if (!file)
327         return error();
328       if (!HS.loadModuleMapFile(*file, is_system))
329         return error();
330     }
331   }
332   if (!HS.lookupModule(module.path.front().GetStringRef())) {
333     error_stream.Printf("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(std::make_pair(
348           &m_compiler_instance->getASTContext().Idents.get(
349               path_component.GetStringRef()),
350           source_manager.getLocForStartOfFile(source_manager.getMainFileID())
351               .getLocWithOffset(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(clang_path.front(), false);
362 
363   if (!top_level_module) {
364     diagnostic_consumer->DumpDiagnostics(error_stream);
365     error_stream.Printf("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(component.GetStringRef());
374     if (!submodule) {
375       diagnostic_consumer->DumpDiagnostics(error_stream);
376       error_stream.Printf("error: Couldn't load submodule %s\n",
377                           component.GetCString());
378       return false;
379     }
380   }
381 
382   clang::Module *requested_module = DoGetModule(clang_path, true);
383 
384   if (requested_module != nullptr) {
385     if (exported_modules)
386       ReportModuleExports(*exported_modules, 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 
LanguageSupportsClangModules(lldb::LanguageType language)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 
AddModulesForCompileUnit(CompileUnit & cu,ClangModulesDeclVendor::ModuleVector & exported_modules,Stream & error_stream)417 bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
418     CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules,
419     Stream &error_stream) {
420   if (LanguageSupportsClangModules(cu.GetLanguage())) {
421     for (auto &imported_module : cu.GetImportedModules())
422       if (!AddModule(imported_module, &exported_modules, error_stream))
423         return false;
424   }
425   return true;
426 }
427 
428 // ClangImporter::lookupValue
429 
430 uint32_t
FindDecls(ConstString name,bool append,uint32_t max_matches,std::vector<CompilerDecl> & decls)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.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       lookup_result,
449       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(m_ast_context->GetCompilerDecl(named_decl));
459     ++num_matches;
460   }
461 
462   return num_matches;
463 }
464 
ForEachMacro(const ClangModulesDeclVendor::ModuleVector & modules,std::function<bool (llvm::StringRef,llvm::StringRef)> handler)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(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)) {
507       clang::Module *module = module_macro->getOwningModule();
508 
509       {
510         ModulePriorityMap::iterator pi =
511             module_priorities.find(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             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(macro_identifier.str());
536 
537       {
538         if (macro_info->isFunctionLike()) {
539           macro_expansion.append("(");
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(", ");
548             else
549               first_arg = false;
550 
551             macro_expansion.append((*pi)->getName().str());
552           }
553 
554           if (macro_info->isC99Varargs()) {
555             if (first_arg)
556               macro_expansion.append("...");
557             else
558               macro_expansion.append(", ...");
559           } else if (macro_info->isGNUVarargs())
560             macro_expansion.append("...");
561 
562           macro_expansion.append(")");
563         }
564 
565         macro_expansion.append(" ");
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(" ");
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(token_str);
582             } else {
583               bool invalid = false;
584               const char *literal_source =
585                   m_compiler_instance->getSourceManager().getCharacterData(
586                       ti->getLocation(), &invalid);
587 
588               if (invalid) {
589                 lldbassert(0 && "Unhandled token kind");
590                 macro_expansion.append("<unknown literal value>");
591               } else {
592                 macro_expansion.append(
593                     std::string(literal_source, ti->getLength()));
594               }
595             }
596           } else if (const char *punctuator_spelling =
597                          clang::tok::getPunctuatorSpelling(ti->getKind())) {
598             macro_expansion.append(punctuator_spelling);
599           } else if (const char *keyword_spelling =
600                          clang::tok::getKeywordSpelling(ti->getKind())) {
601             macro_expansion.append(keyword_spelling);
602           } else {
603             switch (ti->getKind()) {
604             case clang::tok::TokenKind::identifier:
605               macro_expansion.append(ti->getIdentifierInfo()->getName().str());
606               break;
607             case clang::tok::TokenKind::raw_identifier:
608               macro_expansion.append(ti->getRawIdentifier().str());
609               break;
610             default:
611               macro_expansion.append(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
DoGetModule(clang::ModuleIdPath path,bool make_visible)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(path.front().second, path, visibility,
634                                          is_inclusion_directive);
635 }
636 
637 static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer";
638 
639 lldb_private::ClangModulesDeclVendor *
Create(Target & target)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, compiler_invocation_arguments);
667 
668   compiler_invocation_arguments.push_back(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(std::string(path.str()));
678     compiler_invocation_arguments.push_back(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(spi);
685 
686     std::string search_path_argument = "-I";
687     search_path_argument.append(search_path.GetPath());
688 
689     compiler_invocation_arguments.push_back(search_path_argument);
690   }
691 
692   {
693     FileSpec clang_resource_dir = GetClangResourceDir();
694 
695     if (FileSystem::Instance().IsDirectory(clang_resource_dir.GetPath())) {
696       compiler_invocation_arguments.push_back("-resource-dir");
697       compiler_invocation_arguments.push_back(clang_resource_dir.GetPath());
698     }
699   }
700 
701   std::vector<const char *> compiler_invocation_argument_cstrs;
702   compiler_invocation_argument_cstrs.reserve(
703       compiler_invocation_arguments.size());
704   for (const std::string &arg : compiler_invocation_arguments)
705     compiler_invocation_argument_cstrs.push_back(arg.c_str());
706 
707   auto diag_options_up =
708       clang::CreateAndPopulateDiagOpts(compiler_invocation_argument_cstrs);
709   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
710       clang::CompilerInstance::createDiagnostics(diag_options_up.release(),
711                                                  new StoringDiagnosticConsumer);
712 
713   Log *log = GetLog(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(compiler_invocation_argument_cstrs,
722                               std::move(CIOpts));
723 
724   if (!invocation)
725     return nullptr;
726 
727   std::unique_ptr<llvm::MemoryBuffer> source_buffer =
728       llvm::MemoryBuffer::getMemBuffer(
729           "extern int __lldb __attribute__((unavailable));",
730           ModuleImportBufferName);
731 
732   invocation->getPreprocessorOpts().addRemappedFile(ModuleImportBufferName,
733                                                     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(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       *diagnostics_engine, instance->getInvocation().TargetOpts));
747 
748   if (!instance->hasTarget())
749     return nullptr;
750 
751   instance->getTarget().adjust(*diagnostics_engine, instance->getLangOpts());
752 
753   if (!action->BeginSourceFile(*instance,
754                                instance->getFrontendOpts().Inputs[0]))
755     return nullptr;
756 
757   instance->createASTReader();
758 
759   instance->createSema(action->getTranslationUnitKind(), 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(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