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