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