blob: 46adaaff33ce5c5d8d133c52cd79e551b245dc3e [file] [log] [blame]
Sean Callanan9998acd2014-12-05 01:21:59 +00001//===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Sean Callanan9998acd2014-12-05 01:21:59 +000010#include "lldb/Core/StreamString.h"
Zachary Turnerb88ec652014-12-05 17:38:20 +000011#include "lldb/Expression/ClangModulesDeclVendor.h"
Sean Callanan9998acd2014-12-05 01:21:59 +000012#include "lldb/Host/FileSpec.h"
13#include "lldb/Host/Host.h"
14#include "lldb/Host/HostInfo.h"
15#include "lldb/Target/Target.h"
16
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Frontend/CompilerInstance.h"
19#include "clang/Frontend/FrontendActions.h"
20#include "clang/Lex/Preprocessor.h"
21#include "clang/Parse/Parser.h"
22#include "clang/Sema/Lookup.h"
23#include "clang/Serialization/ASTReader.h"
24
Zachary Turnerb88ec652014-12-05 17:38:20 +000025#include <mutex>
26
Sean Callanan9998acd2014-12-05 01:21:59 +000027using namespace lldb_private;
28
29namespace {
30 // Any Clang compiler requires a consumer for diagnostics. This one stores them as strings
31 // so we can provide them to the user in case a module failed to load.
32 class StoringDiagnosticConsumer : public clang::DiagnosticConsumer
33 {
34 public:
35 StoringDiagnosticConsumer ();
36 void
37 HandleDiagnostic (clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info);
38
39 void
40 ClearDiagnostics ();
41
42 void
43 DumpDiagnostics (Stream &error_stream);
44 private:
45 typedef std::pair<clang::DiagnosticsEngine::Level, std::string> IDAndDiagnostic;
46 std::vector<IDAndDiagnostic> m_diagnostics;
47 Log * m_log;
48 };
49
50 // The private implementation of our ClangModulesDeclVendor. Contains all the Clang state required
51 // to load modules.
52 class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor
53 {
54 public:
55 ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine,
56 llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation,
57 std::unique_ptr<clang::CompilerInstance> &&compiler_instance,
58 std::unique_ptr<clang::Parser> &&parser);
59
60 virtual bool
61 AddModule(std::vector<llvm::StringRef> &path,
62 Stream &error_stream);
63
64 virtual uint32_t
65 FindDecls (const ConstString &name,
66 bool append,
67 uint32_t max_matches,
68 std::vector <clang::NamedDecl*> &decls);
69
70 ~ClangModulesDeclVendorImpl();
71
72 private:
73 clang::ModuleLoadResult
74 DoGetModule(clang::ModuleIdPath path, bool make_visible);
75
76 llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine;
77 llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> m_compiler_invocation;
78 std::unique_ptr<clang::CompilerInstance> m_compiler_instance;
79 std::unique_ptr<clang::Parser> m_parser;
80 };
81}
82
83StoringDiagnosticConsumer::StoringDiagnosticConsumer ()
84{
85 m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
86}
87
88void
89StoringDiagnosticConsumer::HandleDiagnostic (clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info)
90{
91 llvm::SmallVector<char, 256> diagnostic_string;
92
93 info.FormatDiagnostic(diagnostic_string);
94
95 m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, std::string(diagnostic_string.data(), diagnostic_string.size())));
96}
97
98void
99StoringDiagnosticConsumer::ClearDiagnostics ()
100{
101 m_diagnostics.clear();
102}
103
104void
105StoringDiagnosticConsumer::DumpDiagnostics (Stream &error_stream)
106{
107 for (IDAndDiagnostic &diag : m_diagnostics)
108 {
109 switch (diag.first)
110 {
111 default:
112 error_stream.PutCString(diag.second.c_str());
Sean Callanan498ff1c2014-12-06 00:56:43 +0000113 error_stream.PutChar('\n');
Sean Callanan9998acd2014-12-05 01:21:59 +0000114 break;
115 case clang::DiagnosticsEngine::Level::Ignored:
116 break;
117 }
118 }
119}
120
121static FileSpec
122GetResourceDir ()
123{
124 static FileSpec g_cached_resource_dir;
125
126 static std::once_flag g_once_flag;
127
128 std::call_once(g_once_flag, [](){
129 HostInfo::GetLLDBPath (lldb::ePathTypeClangDir, g_cached_resource_dir);
130 });
131
132 return g_cached_resource_dir;
133}
134
135
136ClangModulesDeclVendor::ClangModulesDeclVendor()
137{
138}
139
140ClangModulesDeclVendor::~ClangModulesDeclVendor()
141{
142}
143
144ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine,
145 llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation,
146 std::unique_ptr<clang::CompilerInstance> &&compiler_instance,
147 std::unique_ptr<clang::Parser> &&parser) :
148 ClangModulesDeclVendor(),
149 m_diagnostics_engine(diagnostics_engine),
150 m_compiler_invocation(compiler_invocation),
151 m_compiler_instance(std::move(compiler_instance)),
152 m_parser(std::move(parser))
153{
154}
155
156bool
157ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
158 Stream &error_stream)
159{
160 // Fail early.
161
162 if (m_compiler_instance->hadModuleLoaderFatalFailure())
163 {
164 error_stream.PutCString("error: Couldn't load a module because the module loader is in a fatal state.\n");
165 return false;
166 }
167
168 if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0]))
169 {
170 error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].str().c_str());
171 return false;
172 }
173
174 llvm::SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>, 4> clang_path;
175
176 {
177 size_t source_loc_counter = 0;
178 clang::SourceManager &source_manager = m_compiler_instance->getASTContext().getSourceManager();
179
180 for (llvm::StringRef &component : path)
181 {
182 clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(component),
183 source_manager.getLocForStartOfFile(source_manager.getMainFileID()).getLocWithOffset(source_loc_counter++)));
184 }
185 }
186
187 StoringDiagnosticConsumer *diagnostic_consumer = static_cast<StoringDiagnosticConsumer *>(m_compiler_instance->getDiagnostics().getClient());
188
189 diagnostic_consumer->ClearDiagnostics();
190
191 clang::Module *top_level_module = DoGetModule(clang_path.front(), false);
192
193 if (!top_level_module)
194 {
195 diagnostic_consumer->DumpDiagnostics(error_stream);
196 error_stream.Printf("error: Couldn't load top-level module %s\n", path[0].str().c_str());
197 return false;
198 }
199
200 clang::Module *submodule = top_level_module;
201
202 for (size_t ci = 1; ci < path.size(); ++ci)
203 {
204 llvm::StringRef &component = path[ci];
205 submodule = submodule->findSubmodule(component.str());
206 if (!submodule)
207 {
208 diagnostic_consumer->DumpDiagnostics(error_stream);
209 error_stream.Printf("error: Couldn't load submodule %s\n", component.str().c_str());
210 return false;
211 }
212 }
213
214 clang::Module *requested_module = DoGetModule(clang_path, true);
215
216 return (requested_module != nullptr);
217}
218
219// ClangImporter::lookupValue
220
221uint32_t
222ClangModulesDeclVendorImpl::FindDecls (const ConstString &name,
223 bool append,
224 uint32_t max_matches,
225 std::vector <clang::NamedDecl*> &decls)
226{
227 if (!append)
228 decls.clear();
229
230 clang::IdentifierInfo &ident = m_compiler_instance->getASTContext().Idents.get(name.GetStringRef());
231
232 clang::LookupResult lookup_result(m_compiler_instance->getSema(),
233 clang::DeclarationName(&ident),
234 clang::SourceLocation(),
235 clang::Sema::LookupOrdinaryName);
236
237 m_compiler_instance->getSema().LookupName(lookup_result, m_compiler_instance->getSema().getScopeForContext(m_compiler_instance->getASTContext().getTranslationUnitDecl()));
238
239 uint32_t num_matches = 0;
240
241 for (clang::NamedDecl *named_decl : lookup_result)
242 {
243 if (num_matches >= max_matches)
244 return num_matches;
245
246 decls.push_back(named_decl);
247 ++num_matches;
248 }
249
250 return num_matches;
251}
252
253ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl()
254{
255}
256
257clang::ModuleLoadResult
258ClangModulesDeclVendorImpl::DoGetModule(clang::ModuleIdPath path,
259 bool make_visible)
260{
261 clang::Module::NameVisibilityKind visibility = make_visible ? clang::Module::AllVisible : clang::Module::Hidden;
262
263 const bool is_inclusion_directive = false;
264
265 return m_compiler_instance->loadModule(path.front().second, path, visibility, is_inclusion_directive);
266}
267
268static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer";
269
270lldb_private::ClangModulesDeclVendor *
271ClangModulesDeclVendor::Create(Target &target)
272{
273 // FIXME we should insure programmatically that the expression parser's compiler and the modules runtime's
274 // compiler are both initialized in the same way – preferably by the same code.
275
276 if (!target.GetPlatform()->SupportsModules())
277 return nullptr;
278
279 const ArchSpec &arch = target.GetArchitecture();
280
281 std::vector<std::string> compiler_invocation_arguments =
282 {
283 "-fmodules",
284 "-fcxx-modules",
285 "-fsyntax-only",
286 "-femit-all-decls",
287 "-target", arch.GetTriple().str(),
288 "-fmodules-validate-system-headers",
289 "-Werror=non-modular-include-in-framework-module"
290 };
291
292 target.GetPlatform()->AddClangModuleCompilationOptions(compiler_invocation_arguments);
293
294 compiler_invocation_arguments.push_back(ModuleImportBufferName);
295
296 // Add additional search paths with { "-I", path } or { "-F", path } here.
297
298 {
299 llvm::SmallString<128> DefaultModuleCache;
300 const bool erased_on_reboot = false;
301 llvm::sys::path::system_temp_directory(erased_on_reboot, DefaultModuleCache);
302 llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang");
303 llvm::sys::path::append(DefaultModuleCache, "ModuleCache");
304 std::string module_cache_argument("-fmodules-cache-path=");
305 module_cache_argument.append(DefaultModuleCache.str().str());
306 compiler_invocation_arguments.push_back(module_cache_argument);
307 }
308
309 {
310 FileSpec clang_resource_dir = GetResourceDir();
311
312 if (clang_resource_dir.IsDirectory())
313 {
314 compiler_invocation_arguments.push_back("-resource-dir");
315 compiler_invocation_arguments.push_back(clang_resource_dir.GetPath());
316 }
317 }
318
319 llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine = clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions,
320 new StoringDiagnosticConsumer);
321
322 std::vector<const char *> compiler_invocation_argument_cstrs;
323
324 for (const std::string &arg : compiler_invocation_arguments) {
325 compiler_invocation_argument_cstrs.push_back(arg.c_str());
326 }
327
328 llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> invocation(clang::createInvocationFromCommandLine(compiler_invocation_argument_cstrs, diagnostics_engine));
329
330 if (!invocation)
331 return nullptr;
332
333 std::unique_ptr<llvm::MemoryBuffer> source_buffer = llvm::MemoryBuffer::getMemBuffer("extern int __lldb __attribute__((unavailable));",
334 ModuleImportBufferName);
335
336 invocation->getPreprocessorOpts().addRemappedFile(ModuleImportBufferName, source_buffer.release());
337
338 std::unique_ptr<clang::CompilerInstance> instance(new clang::CompilerInstance);
339
340 instance->setDiagnostics(diagnostics_engine.get());
341 instance->setInvocation(invocation.get());
342
343 std::unique_ptr<clang::FrontendAction> action(new clang::SyntaxOnlyAction);
344
345 instance->setTarget(clang::TargetInfo::CreateTargetInfo(*diagnostics_engine, instance->getInvocation().TargetOpts));
346
347 if (!instance->hasTarget())
348 return nullptr;
349
350 instance->getTarget().adjust(instance->getLangOpts());
351
352 if (!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0]))
353 return nullptr;
354
355 instance->getPreprocessor().enableIncrementalProcessing();
356
357 instance->createModuleManager();
358
359 instance->createSema(action->getTranslationUnitKind(), nullptr);
360
361 const bool skipFunctionBodies = false;
362 std::unique_ptr<clang::Parser> parser(new clang::Parser(instance->getPreprocessor(), instance->getSema(), skipFunctionBodies));
363
364 instance->getPreprocessor().EnterMainSourceFile();
365 parser->Initialize();
366
367 clang::Parser::DeclGroupPtrTy parsed;
368
369 while (!parser->ParseTopLevelDecl(parsed));
370
371 return new ClangModulesDeclVendorImpl (diagnostics_engine, invocation, std::move(instance), std::move(parser));
372}