blob: dc07ac738b41d6d1da599223911d38cdb775ec86 [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());
113 break;
114 case clang::DiagnosticsEngine::Level::Ignored:
115 break;
116 }
117 }
118}
119
120static FileSpec
121GetResourceDir ()
122{
123 static FileSpec g_cached_resource_dir;
124
125 static std::once_flag g_once_flag;
126
127 std::call_once(g_once_flag, [](){
128 HostInfo::GetLLDBPath (lldb::ePathTypeClangDir, g_cached_resource_dir);
129 });
130
131 return g_cached_resource_dir;
132}
133
134
135ClangModulesDeclVendor::ClangModulesDeclVendor()
136{
137}
138
139ClangModulesDeclVendor::~ClangModulesDeclVendor()
140{
141}
142
143ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine,
144 llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation,
145 std::unique_ptr<clang::CompilerInstance> &&compiler_instance,
146 std::unique_ptr<clang::Parser> &&parser) :
147 ClangModulesDeclVendor(),
148 m_diagnostics_engine(diagnostics_engine),
149 m_compiler_invocation(compiler_invocation),
150 m_compiler_instance(std::move(compiler_instance)),
151 m_parser(std::move(parser))
152{
153}
154
155bool
156ClangModulesDeclVendorImpl::AddModule(std::vector<llvm::StringRef> &path,
157 Stream &error_stream)
158{
159 // Fail early.
160
161 if (m_compiler_instance->hadModuleLoaderFatalFailure())
162 {
163 error_stream.PutCString("error: Couldn't load a module because the module loader is in a fatal state.\n");
164 return false;
165 }
166
167 if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0]))
168 {
169 error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].str().c_str());
170 return false;
171 }
172
173 llvm::SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>, 4> clang_path;
174
175 {
176 size_t source_loc_counter = 0;
177 clang::SourceManager &source_manager = m_compiler_instance->getASTContext().getSourceManager();
178
179 for (llvm::StringRef &component : path)
180 {
181 clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(component),
182 source_manager.getLocForStartOfFile(source_manager.getMainFileID()).getLocWithOffset(source_loc_counter++)));
183 }
184 }
185
186 StoringDiagnosticConsumer *diagnostic_consumer = static_cast<StoringDiagnosticConsumer *>(m_compiler_instance->getDiagnostics().getClient());
187
188 diagnostic_consumer->ClearDiagnostics();
189
190 clang::Module *top_level_module = DoGetModule(clang_path.front(), false);
191
192 if (!top_level_module)
193 {
194 diagnostic_consumer->DumpDiagnostics(error_stream);
195 error_stream.Printf("error: Couldn't load top-level module %s\n", path[0].str().c_str());
196 return false;
197 }
198
199 clang::Module *submodule = top_level_module;
200
201 for (size_t ci = 1; ci < path.size(); ++ci)
202 {
203 llvm::StringRef &component = path[ci];
204 submodule = submodule->findSubmodule(component.str());
205 if (!submodule)
206 {
207 diagnostic_consumer->DumpDiagnostics(error_stream);
208 error_stream.Printf("error: Couldn't load submodule %s\n", component.str().c_str());
209 return false;
210 }
211 }
212
213 clang::Module *requested_module = DoGetModule(clang_path, true);
214
215 return (requested_module != nullptr);
216}
217
218// ClangImporter::lookupValue
219
220uint32_t
221ClangModulesDeclVendorImpl::FindDecls (const ConstString &name,
222 bool append,
223 uint32_t max_matches,
224 std::vector <clang::NamedDecl*> &decls)
225{
226 if (!append)
227 decls.clear();
228
229 clang::IdentifierInfo &ident = m_compiler_instance->getASTContext().Idents.get(name.GetStringRef());
230
231 clang::LookupResult lookup_result(m_compiler_instance->getSema(),
232 clang::DeclarationName(&ident),
233 clang::SourceLocation(),
234 clang::Sema::LookupOrdinaryName);
235
236 m_compiler_instance->getSema().LookupName(lookup_result, m_compiler_instance->getSema().getScopeForContext(m_compiler_instance->getASTContext().getTranslationUnitDecl()));
237
238 uint32_t num_matches = 0;
239
240 for (clang::NamedDecl *named_decl : lookup_result)
241 {
242 if (num_matches >= max_matches)
243 return num_matches;
244
245 decls.push_back(named_decl);
246 ++num_matches;
247 }
248
249 return num_matches;
250}
251
252ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl()
253{
254}
255
256clang::ModuleLoadResult
257ClangModulesDeclVendorImpl::DoGetModule(clang::ModuleIdPath path,
258 bool make_visible)
259{
260 clang::Module::NameVisibilityKind visibility = make_visible ? clang::Module::AllVisible : clang::Module::Hidden;
261
262 const bool is_inclusion_directive = false;
263
264 return m_compiler_instance->loadModule(path.front().second, path, visibility, is_inclusion_directive);
265}
266
267static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer";
268
269lldb_private::ClangModulesDeclVendor *
270ClangModulesDeclVendor::Create(Target &target)
271{
272 // FIXME we should insure programmatically that the expression parser's compiler and the modules runtime's
273 // compiler are both initialized in the same way – preferably by the same code.
274
275 if (!target.GetPlatform()->SupportsModules())
276 return nullptr;
277
278 const ArchSpec &arch = target.GetArchitecture();
279
280 std::vector<std::string> compiler_invocation_arguments =
281 {
282 "-fmodules",
283 "-fcxx-modules",
284 "-fsyntax-only",
285 "-femit-all-decls",
286 "-target", arch.GetTriple().str(),
287 "-fmodules-validate-system-headers",
288 "-Werror=non-modular-include-in-framework-module"
289 };
290
291 target.GetPlatform()->AddClangModuleCompilationOptions(compiler_invocation_arguments);
292
293 compiler_invocation_arguments.push_back(ModuleImportBufferName);
294
295 // Add additional search paths with { "-I", path } or { "-F", path } here.
296
297 {
298 llvm::SmallString<128> DefaultModuleCache;
299 const bool erased_on_reboot = false;
300 llvm::sys::path::system_temp_directory(erased_on_reboot, DefaultModuleCache);
301 llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang");
302 llvm::sys::path::append(DefaultModuleCache, "ModuleCache");
303 std::string module_cache_argument("-fmodules-cache-path=");
304 module_cache_argument.append(DefaultModuleCache.str().str());
305 compiler_invocation_arguments.push_back(module_cache_argument);
306 }
307
308 {
309 FileSpec clang_resource_dir = GetResourceDir();
310
311 if (clang_resource_dir.IsDirectory())
312 {
313 compiler_invocation_arguments.push_back("-resource-dir");
314 compiler_invocation_arguments.push_back(clang_resource_dir.GetPath());
315 }
316 }
317
318 llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine = clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions,
319 new StoringDiagnosticConsumer);
320
321 std::vector<const char *> compiler_invocation_argument_cstrs;
322
323 for (const std::string &arg : compiler_invocation_arguments) {
324 compiler_invocation_argument_cstrs.push_back(arg.c_str());
325 }
326
327 llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> invocation(clang::createInvocationFromCommandLine(compiler_invocation_argument_cstrs, diagnostics_engine));
328
329 if (!invocation)
330 return nullptr;
331
332 std::unique_ptr<llvm::MemoryBuffer> source_buffer = llvm::MemoryBuffer::getMemBuffer("extern int __lldb __attribute__((unavailable));",
333 ModuleImportBufferName);
334
335 invocation->getPreprocessorOpts().addRemappedFile(ModuleImportBufferName, source_buffer.release());
336
337 std::unique_ptr<clang::CompilerInstance> instance(new clang::CompilerInstance);
338
339 instance->setDiagnostics(diagnostics_engine.get());
340 instance->setInvocation(invocation.get());
341
342 std::unique_ptr<clang::FrontendAction> action(new clang::SyntaxOnlyAction);
343
344 instance->setTarget(clang::TargetInfo::CreateTargetInfo(*diagnostics_engine, instance->getInvocation().TargetOpts));
345
346 if (!instance->hasTarget())
347 return nullptr;
348
349 instance->getTarget().adjust(instance->getLangOpts());
350
351 if (!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0]))
352 return nullptr;
353
354 instance->getPreprocessor().enableIncrementalProcessing();
355
356 instance->createModuleManager();
357
358 instance->createSema(action->getTranslationUnitKind(), nullptr);
359
360 const bool skipFunctionBodies = false;
361 std::unique_ptr<clang::Parser> parser(new clang::Parser(instance->getPreprocessor(), instance->getSema(), skipFunctionBodies));
362
363 instance->getPreprocessor().EnterMainSourceFile();
364 parser->Initialize();
365
366 clang::Parser::DeclGroupPtrTy parsed;
367
368 while (!parser->ParseTopLevelDecl(parsed));
369
370 return new ClangModulesDeclVendorImpl (diagnostics_engine, invocation, std::move(instance), std::move(parser));
371}