blob: 84f7bec91924729d866f8399604c43fc795a84b7 [file] [log] [blame]
Douglas Gregora30cfe52011-11-11 19:10:28 +00001//===--- ModuleMap.cpp - Describe the layout of modules ---------*- 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//
10// This file defines the ModuleMap implementation, which describes the layout
11// of a module as it relates to headers.
12//
13//===----------------------------------------------------------------------===//
14#include "clang/Lex/ModuleMap.h"
15#include "clang/Lex/Lexer.h"
16#include "clang/Lex/LiteralSupport.h"
17#include "clang/Lex/LexDiagnostic.h"
18#include "clang/Basic/Diagnostic.h"
19#include "clang/Basic/FileManager.h"
20#include "clang/Basic/TargetInfo.h"
21#include "clang/Basic/TargetOptions.h"
22#include "llvm/Support/Allocator.h"
23#include "llvm/Support/Host.h"
Douglas Gregor8b6d3de2011-11-11 21:55:48 +000024#include "llvm/Support/PathV2.h"
Douglas Gregora30cfe52011-11-11 19:10:28 +000025#include "llvm/Support/raw_ostream.h"
26#include "llvm/ADT/StringRef.h"
27#include "llvm/ADT/StringSwitch.h"
28using namespace clang;
29
Douglas Gregor90db2602011-12-02 01:47:07 +000030Module::ExportDecl
31ModuleMap::resolveExport(Module *Mod,
32 const Module::UnresolvedExportDecl &Unresolved,
33 bool Complain) {
34 // Find the starting module.
35 Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
36 if (!Context) {
37 if (Complain)
38 Diags->Report(Unresolved.Id[0].second,
39 diag::err_mmap_missing_module_unqualified)
40 << Unresolved.Id[0].first << Mod->getFullModuleName();
41
42 return Module::ExportDecl();
43 }
44
45 // Dig into the module path.
46 for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) {
47 Module *Sub = lookupModuleQualified(Unresolved.Id[I].first,
48 Context);
49 if (!Sub) {
50 if (Complain)
51 Diags->Report(Unresolved.Id[I].second,
52 diag::err_mmap_missing_module_qualified)
53 << Unresolved.Id[I].first << Context->getFullModuleName()
54 << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second);
55
56 return Module::ExportDecl();
57 }
58
59 Context = Sub;
60 }
61
62 return Module::ExportDecl(Context, Unresolved.Wildcard);
63}
64
Douglas Gregora30cfe52011-11-11 19:10:28 +000065ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC) {
66 llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
67 Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
68 new DiagnosticsEngine(DiagIDs));
69 Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true);
70 SourceMgr = new SourceManager(*Diags, FileMgr);
71}
72
73ModuleMap::~ModuleMap() {
Douglas Gregor09fe1bb2011-11-17 02:05:44 +000074 for (llvm::StringMap<Module *>::iterator I = Modules.begin(),
75 IEnd = Modules.end();
76 I != IEnd; ++I) {
77 delete I->getValue();
78 }
79
Douglas Gregora30cfe52011-11-11 19:10:28 +000080 delete SourceMgr;
81}
82
Douglas Gregor1a4761e2011-11-30 23:21:26 +000083Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
Douglas Gregor65f3b5e2011-11-11 22:18:48 +000084 llvm::DenseMap<const FileEntry *, Module *>::iterator Known
85 = Headers.find(File);
86 if (Known != Headers.end())
87 return Known->second;
88
Douglas Gregoradb97992011-11-16 23:02:25 +000089 const DirectoryEntry *Dir = File->getDir();
90 llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
91 = UmbrellaDirs.find(Dir);
92 if (KnownDir != UmbrellaDirs.end())
93 return KnownDir->second;
94
95 // Walk up the directory hierarchy looking for umbrella headers.
96 llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
97 StringRef DirName = Dir->getName();
98 do {
99 // Retrieve our parent path.
100 DirName = llvm::sys::path::parent_path(DirName);
101 if (DirName.empty())
102 break;
103
104 // Resolve the parent path to a directory entry.
105 Dir = SourceMgr->getFileManager().getDirectory(DirName);
106 if (!Dir)
107 break;
108
109 KnownDir = UmbrellaDirs.find(Dir);
110 if (KnownDir != UmbrellaDirs.end()) {
111 Module *Result = KnownDir->second;
112
113 // Record each of the directories we stepped through as being part of
114 // the module we found, since the umbrella header covers them all.
115 for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
116 UmbrellaDirs[SkippedDirs[I]] = Result;
117
118 return Result;
119 }
120
121 SkippedDirs.push_back(Dir);
122 } while (true);
123
Douglas Gregor65f3b5e2011-11-11 22:18:48 +0000124 return 0;
125}
126
Douglas Gregor1a4761e2011-11-30 23:21:26 +0000127Module *ModuleMap::findModule(StringRef Name) {
Douglas Gregor484535e2011-11-11 23:20:24 +0000128 llvm::StringMap<Module *>::iterator Known = Modules.find(Name);
129 if (Known != Modules.end())
130 return Known->getValue();
131
132 return 0;
133}
134
Douglas Gregor90db2602011-12-02 01:47:07 +0000135Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
136 for(; Context; Context = Context->Parent) {
137 if (Module *Sub = lookupModuleQualified(Name, Context))
138 return Sub;
139 }
140
141 return findModule(Name);
142}
143
144Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) {
145 if (!Context)
146 return findModule(Name);
147
148 llvm::StringMap<Module *>::iterator Sub = Context->SubModules.find(Name);
149 if (Sub != Context->SubModules.end())
150 return Sub->getValue();
151
152 return 0;
153}
154
Douglas Gregor1a4761e2011-11-30 23:21:26 +0000155std::pair<Module *, bool>
Douglas Gregor392ed2b2011-11-30 17:33:56 +0000156ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
157 bool IsExplicit) {
158 // Try to find an existing module with this name.
159 if (Module *Found = Parent? Parent->SubModules[Name] : Modules[Name])
160 return std::make_pair(Found, false);
161
162 // Create a new module with this name.
163 Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
164 IsExplicit);
165 if (Parent)
166 Parent->SubModules[Name] = Result;
167 else
168 Modules[Name] = Result;
169 return std::make_pair(Result, true);
170}
171
Douglas Gregor1a4761e2011-11-30 23:21:26 +0000172Module *
Douglas Gregor2821c7f2011-11-17 01:41:17 +0000173ModuleMap::inferFrameworkModule(StringRef ModuleName,
174 const DirectoryEntry *FrameworkDir) {
175 // Check whether we've already found this module.
176 if (Module *Module = findModule(ModuleName))
177 return Module;
178
179 // Look for an umbrella header.
180 llvm::SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
181 llvm::sys::path::append(UmbrellaName, "Headers");
182 llvm::sys::path::append(UmbrellaName, ModuleName + ".h");
183 const FileEntry *UmbrellaHeader
184 = SourceMgr->getFileManager().getFile(UmbrellaName);
185
186 // FIXME: If there's no umbrella header, we could probably scan the
187 // framework to load *everything*. But, it's not clear that this is a good
188 // idea.
189 if (!UmbrellaHeader)
190 return 0;
191
Douglas Gregora8654052011-11-17 22:09:43 +0000192 Module *Result = new Module(ModuleName, SourceLocation(),
193 /*IsFramework=*/true);
Douglas Gregor2821c7f2011-11-17 01:41:17 +0000194 Result->UmbrellaHeader = UmbrellaHeader;
195 Headers[UmbrellaHeader] = Result;
196 UmbrellaDirs[FrameworkDir] = Result;
197 Modules[ModuleName] = Result;
198 return Result;
199}
200
Douglas Gregorf9e357d2011-11-29 19:06:37 +0000201const FileEntry *
Douglas Gregor1a4761e2011-11-30 23:21:26 +0000202ModuleMap::getContainingModuleMapFile(Module *Module) {
Douglas Gregorf9e357d2011-11-29 19:06:37 +0000203 if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
204 return 0;
205
206 return SourceMgr->getFileEntryForID(
207 SourceMgr->getFileID(Module->DefinitionLoc));
208}
209
Douglas Gregora30cfe52011-11-11 19:10:28 +0000210void ModuleMap::dump() {
211 llvm::errs() << "Modules:";
212 for (llvm::StringMap<Module *>::iterator M = Modules.begin(),
213 MEnd = Modules.end();
214 M != MEnd; ++M)
Douglas Gregor804c3bf2011-11-29 18:17:59 +0000215 M->getValue()->print(llvm::errs(), 2);
Douglas Gregora30cfe52011-11-11 19:10:28 +0000216
217 llvm::errs() << "Headers:";
218 for (llvm::DenseMap<const FileEntry *, Module *>::iterator
219 H = Headers.begin(),
220 HEnd = Headers.end();
221 H != HEnd; ++H) {
222 llvm::errs() << " \"" << H->first->getName() << "\" -> "
223 << H->second->getFullModuleName() << "\n";
224 }
225}
226
Douglas Gregor90db2602011-12-02 01:47:07 +0000227bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
228 bool HadError = false;
229 for (unsigned I = 0, N = Mod->UnresolvedExports.size(); I != N; ++I) {
230 Module::ExportDecl Export = resolveExport(Mod, Mod->UnresolvedExports[I],
231 Complain);
232 if (Export.getPointer())
233 Mod->Exports.push_back(Export);
234 else
235 HadError = true;
236 }
237 Mod->UnresolvedExports.clear();
238 return HadError;
239}
240
Douglas Gregora30cfe52011-11-11 19:10:28 +0000241//----------------------------------------------------------------------------//
242// Module map file parser
243//----------------------------------------------------------------------------//
244
245namespace clang {
246 /// \brief A token in a module map file.
247 struct MMToken {
248 enum TokenKind {
249 EndOfFile,
250 HeaderKeyword,
251 Identifier,
252 ExplicitKeyword,
Douglas Gregor90db2602011-12-02 01:47:07 +0000253 ExportKeyword,
Douglas Gregora8654052011-11-17 22:09:43 +0000254 FrameworkKeyword,
Douglas Gregora30cfe52011-11-11 19:10:28 +0000255 ModuleKeyword,
Douglas Gregor90db2602011-12-02 01:47:07 +0000256 Period,
Douglas Gregora30cfe52011-11-11 19:10:28 +0000257 UmbrellaKeyword,
Douglas Gregor90db2602011-12-02 01:47:07 +0000258 Star,
Douglas Gregora30cfe52011-11-11 19:10:28 +0000259 StringLiteral,
260 LBrace,
261 RBrace
262 } Kind;
263
264 unsigned Location;
265 unsigned StringLength;
266 const char *StringData;
267
268 void clear() {
269 Kind = EndOfFile;
270 Location = 0;
271 StringLength = 0;
272 StringData = 0;
273 }
274
275 bool is(TokenKind K) const { return Kind == K; }
276
277 SourceLocation getLocation() const {
278 return SourceLocation::getFromRawEncoding(Location);
279 }
280
281 StringRef getString() const {
282 return StringRef(StringData, StringLength);
283 }
284 };
285
286 class ModuleMapParser {
287 Lexer &L;
288 SourceManager &SourceMgr;
289 DiagnosticsEngine &Diags;
290 ModuleMap &Map;
291
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000292 /// \brief The directory that this module map resides in.
293 const DirectoryEntry *Directory;
294
Douglas Gregora30cfe52011-11-11 19:10:28 +0000295 /// \brief Whether an error occurred.
296 bool HadError;
297
298 /// \brief Default target information, used only for string literal
299 /// parsing.
300 TargetInfo *Target;
301
302 /// \brief Stores string data for the various string literals referenced
303 /// during parsing.
304 llvm::BumpPtrAllocator StringData;
305
306 /// \brief The current token.
307 MMToken Tok;
308
309 /// \brief The active module.
Douglas Gregor1a4761e2011-11-30 23:21:26 +0000310 Module *ActiveModule;
Douglas Gregora30cfe52011-11-11 19:10:28 +0000311
312 /// \brief Consume the current token and return its location.
313 SourceLocation consumeToken();
314
315 /// \brief Skip tokens until we reach the a token with the given kind
316 /// (or the end of the file).
317 void skipUntil(MMToken::TokenKind K);
318
319 void parseModuleDecl();
320 void parseUmbrellaDecl();
321 void parseHeaderDecl();
Douglas Gregor90db2602011-12-02 01:47:07 +0000322 void parseExportDecl();
Douglas Gregora30cfe52011-11-11 19:10:28 +0000323
324 public:
Douglas Gregora30cfe52011-11-11 19:10:28 +0000325 explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
326 DiagnosticsEngine &Diags,
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000327 ModuleMap &Map,
328 const DirectoryEntry *Directory)
329 : L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map),
330 Directory(Directory), HadError(false), ActiveModule(0)
Douglas Gregora30cfe52011-11-11 19:10:28 +0000331 {
332 TargetOptions TargetOpts;
333 TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
334 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
335
336 Tok.clear();
337 consumeToken();
338 }
339
340 bool parseModuleMapFile();
341 };
342}
343
344SourceLocation ModuleMapParser::consumeToken() {
345retry:
346 SourceLocation Result = Tok.getLocation();
347 Tok.clear();
348
349 Token LToken;
350 L.LexFromRawLexer(LToken);
351 Tok.Location = LToken.getLocation().getRawEncoding();
352 switch (LToken.getKind()) {
353 case tok::raw_identifier:
354 Tok.StringData = LToken.getRawIdentifierData();
355 Tok.StringLength = LToken.getLength();
356 Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
357 .Case("header", MMToken::HeaderKeyword)
358 .Case("explicit", MMToken::ExplicitKeyword)
Douglas Gregor90db2602011-12-02 01:47:07 +0000359 .Case("export", MMToken::ExportKeyword)
Douglas Gregora8654052011-11-17 22:09:43 +0000360 .Case("framework", MMToken::FrameworkKeyword)
Douglas Gregora30cfe52011-11-11 19:10:28 +0000361 .Case("module", MMToken::ModuleKeyword)
362 .Case("umbrella", MMToken::UmbrellaKeyword)
363 .Default(MMToken::Identifier);
364 break;
365
366 case tok::eof:
367 Tok.Kind = MMToken::EndOfFile;
368 break;
369
370 case tok::l_brace:
371 Tok.Kind = MMToken::LBrace;
372 break;
373
Douglas Gregor90db2602011-12-02 01:47:07 +0000374 case tok::period:
375 Tok.Kind = MMToken::Period;
376 break;
377
Douglas Gregora30cfe52011-11-11 19:10:28 +0000378 case tok::r_brace:
379 Tok.Kind = MMToken::RBrace;
380 break;
381
Douglas Gregor90db2602011-12-02 01:47:07 +0000382 case tok::star:
383 Tok.Kind = MMToken::Star;
384 break;
385
Douglas Gregora30cfe52011-11-11 19:10:28 +0000386 case tok::string_literal: {
387 // Parse the string literal.
388 LangOptions LangOpts;
389 StringLiteralParser StringLiteral(&LToken, 1, SourceMgr, LangOpts, *Target);
390 if (StringLiteral.hadError)
391 goto retry;
392
393 // Copy the string literal into our string data allocator.
394 unsigned Length = StringLiteral.GetStringLength();
395 char *Saved = StringData.Allocate<char>(Length + 1);
396 memcpy(Saved, StringLiteral.GetString().data(), Length);
397 Saved[Length] = 0;
398
399 // Form the token.
400 Tok.Kind = MMToken::StringLiteral;
401 Tok.StringData = Saved;
402 Tok.StringLength = Length;
403 break;
404 }
405
406 case tok::comment:
407 goto retry;
408
409 default:
410 Diags.Report(LToken.getLocation(), diag::err_mmap_unknown_token);
411 HadError = true;
412 goto retry;
413 }
414
415 return Result;
416}
417
418void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
419 unsigned braceDepth = 0;
420 do {
421 switch (Tok.Kind) {
422 case MMToken::EndOfFile:
423 return;
424
425 case MMToken::LBrace:
426 if (Tok.is(K) && braceDepth == 0)
427 return;
428
429 ++braceDepth;
430 break;
431
432 case MMToken::RBrace:
433 if (braceDepth > 0)
434 --braceDepth;
435 else if (Tok.is(K))
436 return;
437 break;
438
439 default:
440 if (braceDepth == 0 && Tok.is(K))
441 return;
442 break;
443 }
444
445 consumeToken();
446 } while (true);
447}
448
449/// \brief Parse a module declaration.
450///
451/// module-declaration:
Douglas Gregora8654052011-11-17 22:09:43 +0000452/// 'framework'[opt] 'module' identifier { module-member* }
Douglas Gregora30cfe52011-11-11 19:10:28 +0000453///
454/// module-member:
455/// umbrella-declaration
456/// header-declaration
457/// 'explicit'[opt] module-declaration
Douglas Gregor90db2602011-12-02 01:47:07 +0000458/// export-declaration
Douglas Gregora30cfe52011-11-11 19:10:28 +0000459void ModuleMapParser::parseModuleDecl() {
Douglas Gregora8654052011-11-17 22:09:43 +0000460 assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
461 Tok.is(MMToken::FrameworkKeyword));
462
463 // Parse 'framework' or 'explicit' keyword, if present.
464 bool Framework = false;
Douglas Gregora30cfe52011-11-11 19:10:28 +0000465 bool Explicit = false;
Douglas Gregora8654052011-11-17 22:09:43 +0000466
467 if (Tok.is(MMToken::FrameworkKeyword)) {
468 consumeToken();
469 Framework = true;
470 }
471 // Parse 'explicit' keyword, if present.
472 else if (Tok.is(MMToken::ExplicitKeyword)) {
Douglas Gregora30cfe52011-11-11 19:10:28 +0000473 consumeToken();
474 Explicit = true;
475 }
476
477 // Parse 'module' keyword.
478 if (!Tok.is(MMToken::ModuleKeyword)) {
479 Diags.Report(Tok.getLocation(),
480 diag::err_mmap_expected_module_after_explicit);
481 consumeToken();
482 HadError = true;
483 return;
484 }
485 consumeToken(); // 'module' keyword
486
487 // Parse the module name.
488 if (!Tok.is(MMToken::Identifier)) {
489 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
490 HadError = true;
491 return;
492 }
493 StringRef ModuleName = Tok.getString();
494 SourceLocation ModuleNameLoc = consumeToken();
495
496 // Parse the opening brace.
497 if (!Tok.is(MMToken::LBrace)) {
498 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
499 << ModuleName;
500 HadError = true;
501 return;
502 }
503 SourceLocation LBraceLoc = consumeToken();
504
505 // Determine whether this (sub)module has already been defined.
506 llvm::StringMap<Module *> &ModuleSpace
507 = ActiveModule? ActiveModule->SubModules : Map.Modules;
508 llvm::StringMap<Module *>::iterator ExistingModule
509 = ModuleSpace.find(ModuleName);
510 if (ExistingModule != ModuleSpace.end()) {
511 Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
512 << ModuleName;
513 Diags.Report(ExistingModule->getValue()->DefinitionLoc,
514 diag::note_mmap_prev_definition);
515
516 // Skip the module definition.
517 skipUntil(MMToken::RBrace);
518 if (Tok.is(MMToken::RBrace))
519 consumeToken();
520
521 HadError = true;
522 return;
523 }
524
525 // Start defining this module.
Douglas Gregora8654052011-11-17 22:09:43 +0000526 ActiveModule = new Module(ModuleName, ModuleNameLoc, ActiveModule, Framework,
527 Explicit);
Douglas Gregora30cfe52011-11-11 19:10:28 +0000528 ModuleSpace[ModuleName] = ActiveModule;
529
530 bool Done = false;
531 do {
532 switch (Tok.Kind) {
533 case MMToken::EndOfFile:
534 case MMToken::RBrace:
535 Done = true;
536 break;
537
538 case MMToken::ExplicitKeyword:
539 case MMToken::ModuleKeyword:
540 parseModuleDecl();
541 break;
542
Douglas Gregor90db2602011-12-02 01:47:07 +0000543 case MMToken::ExportKeyword:
544 parseExportDecl();
545 break;
546
Douglas Gregora30cfe52011-11-11 19:10:28 +0000547 case MMToken::HeaderKeyword:
548 parseHeaderDecl();
549 break;
550
551 case MMToken::UmbrellaKeyword:
552 parseUmbrellaDecl();
553 break;
Douglas Gregor90db2602011-12-02 01:47:07 +0000554
Douglas Gregora30cfe52011-11-11 19:10:28 +0000555 default:
556 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
557 consumeToken();
558 break;
559 }
560 } while (!Done);
561
562 if (Tok.is(MMToken::RBrace))
563 consumeToken();
564 else {
565 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
566 Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
567 HadError = true;
568 }
569
570 // We're done parsing this module. Pop back to our parent scope.
571 ActiveModule = ActiveModule->Parent;
572}
573
574/// \brief Parse an umbrella header declaration.
575///
576/// umbrella-declaration:
577/// 'umbrella' string-literal
578void ModuleMapParser::parseUmbrellaDecl() {
579 assert(Tok.is(MMToken::UmbrellaKeyword));
580 SourceLocation UmbrellaLoc = consumeToken();
581
582 // Parse the header name.
583 if (!Tok.is(MMToken::StringLiteral)) {
584 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
585 << "umbrella";
586 HadError = true;
587 return;
588 }
589 StringRef FileName = Tok.getString();
590 SourceLocation FileNameLoc = consumeToken();
591
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000592 // Check whether we already have an umbrella header.
593 if (ActiveModule->UmbrellaHeader) {
594 Diags.Report(FileNameLoc, diag::err_mmap_umbrella_header_conflict)
595 << ActiveModule->getFullModuleName()
596 << ActiveModule->UmbrellaHeader->getName();
597 HadError = true;
598 return;
599 }
600
601 // Only top-level modules can have umbrella headers.
602 if (ActiveModule->Parent) {
603 Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_header_submodule)
604 << ActiveModule->getFullModuleName();
605 HadError = true;
606 return;
607 }
608
609 // Look for this file.
610 llvm::SmallString<128> PathName;
Douglas Gregora8654052011-11-17 22:09:43 +0000611 const FileEntry *File = 0;
Douglas Gregor18ee5472011-11-29 21:59:16 +0000612
613 if (llvm::sys::path::is_absolute(FileName)) {
614 PathName = FileName;
Douglas Gregora8654052011-11-17 22:09:43 +0000615 File = SourceMgr.getFileManager().getFile(PathName);
Douglas Gregor18ee5472011-11-29 21:59:16 +0000616 } else {
617 // Search for the header file within the search directory.
618 PathName += Directory->getName();
619 unsigned PathLength = PathName.size();
620 if (ActiveModule->isPartOfFramework()) {
621 // Check whether this file is in the public headers.
622 llvm::sys::path::append(PathName, "Headers");
623 llvm::sys::path::append(PathName, FileName);
624 File = SourceMgr.getFileManager().getFile(PathName);
Douglas Gregora8654052011-11-17 22:09:43 +0000625
Douglas Gregor18ee5472011-11-29 21:59:16 +0000626 if (!File) {
627 // Check whether this file is in the private headers.
628 PathName.resize(PathLength);
629 llvm::sys::path::append(PathName, "PrivateHeaders");
630 llvm::sys::path::append(PathName, FileName);
631 File = SourceMgr.getFileManager().getFile(PathName);
632 }
633
634 // FIXME: Deal with subframeworks.
635 } else {
636 // Lookup for normal headers.
Douglas Gregora8654052011-11-17 22:09:43 +0000637 llvm::sys::path::append(PathName, FileName);
638 File = SourceMgr.getFileManager().getFile(PathName);
639 }
Douglas Gregora8654052011-11-17 22:09:43 +0000640 }
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000641
642 // FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
643 // Come up with a lazy way to do this.
Douglas Gregora8654052011-11-17 22:09:43 +0000644 if (File) {
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000645 if (const Module *OwningModule = Map.Headers[File]) {
646 Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
647 << FileName << OwningModule->getFullModuleName();
648 HadError = true;
Douglas Gregoradb97992011-11-16 23:02:25 +0000649 } else if ((OwningModule = Map.UmbrellaDirs[Directory])) {
650 Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
651 << OwningModule->getFullModuleName();
652 HadError = true;
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000653 } else {
654 // Record this umbrella header.
655 ActiveModule->UmbrellaHeader = File;
656 Map.Headers[File] = ActiveModule;
Douglas Gregoradb97992011-11-16 23:02:25 +0000657 Map.UmbrellaDirs[Directory] = ActiveModule;
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000658 }
659 } else {
660 Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
661 << true << FileName;
662 HadError = true;
663 }
Douglas Gregora30cfe52011-11-11 19:10:28 +0000664}
665
666/// \brief Parse a header declaration.
667///
668/// header-declaration:
669/// 'header' string-literal
670void ModuleMapParser::parseHeaderDecl() {
671 assert(Tok.is(MMToken::HeaderKeyword));
Benjamin Kramerc96c7212011-11-13 16:52:09 +0000672 consumeToken();
673
Douglas Gregora30cfe52011-11-11 19:10:28 +0000674 // Parse the header name.
675 if (!Tok.is(MMToken::StringLiteral)) {
676 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
677 << "header";
678 HadError = true;
679 return;
680 }
681 StringRef FileName = Tok.getString();
682 SourceLocation FileNameLoc = consumeToken();
683
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000684 // Look for this file.
685 llvm::SmallString<128> PathName;
Douglas Gregor18ee5472011-11-29 21:59:16 +0000686 if (llvm::sys::path::is_relative(FileName)) {
687 // FIXME: Change this search to also look for private headers!
688 PathName += Directory->getName();
689
690 if (ActiveModule->isPartOfFramework())
691 llvm::sys::path::append(PathName, "Headers");
692 }
Douglas Gregora8654052011-11-17 22:09:43 +0000693
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000694 llvm::sys::path::append(PathName, FileName);
695
696 // FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
697 // Come up with a lazy way to do this.
698 if (const FileEntry *File = SourceMgr.getFileManager().getFile(PathName)) {
699 if (const Module *OwningModule = Map.Headers[File]) {
700 Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
701 << FileName << OwningModule->getFullModuleName();
702 HadError = true;
703 } else {
704 // Record this file.
705 ActiveModule->Headers.push_back(File);
706 Map.Headers[File] = ActiveModule;
707 }
708 } else {
709 Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
710 << false << FileName;
711 HadError = true;
712 }
Douglas Gregora30cfe52011-11-11 19:10:28 +0000713}
714
Douglas Gregor90db2602011-12-02 01:47:07 +0000715/// \brief Parse a module export declaration.
716///
717/// export-declaration:
718/// 'export' wildcard-module-id
719///
720/// wildcard-module-id:
721/// identifier
722/// '*'
723/// identifier '.' wildcard-module-id
724void ModuleMapParser::parseExportDecl() {
725 assert(Tok.is(MMToken::ExportKeyword));
726 SourceLocation ExportLoc = consumeToken();
727
728 // Parse the module-id with an optional wildcard at the end.
729 ModuleId ParsedModuleId;
730 bool Wildcard = false;
731 do {
732 if (Tok.is(MMToken::Identifier)) {
733 ParsedModuleId.push_back(std::make_pair(Tok.getString(),
734 Tok.getLocation()));
735 consumeToken();
736
737 if (Tok.is(MMToken::Period)) {
738 consumeToken();
739 continue;
740 }
741
742 break;
743 }
744
745 if(Tok.is(MMToken::Star)) {
746 Wildcard = true;
747 break;
748 }
749
750 Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
751 HadError = true;
752 return;
753 } while (true);
754
755 Module::UnresolvedExportDecl Unresolved = {
756 ExportLoc, ParsedModuleId, Wildcard
757 };
758 ActiveModule->UnresolvedExports.push_back(Unresolved);
759}
760
Douglas Gregora30cfe52011-11-11 19:10:28 +0000761/// \brief Parse a module map file.
762///
763/// module-map-file:
764/// module-declaration*
765bool ModuleMapParser::parseModuleMapFile() {
766 do {
767 switch (Tok.Kind) {
768 case MMToken::EndOfFile:
769 return HadError;
770
771 case MMToken::ModuleKeyword:
Douglas Gregora8654052011-11-17 22:09:43 +0000772 case MMToken::FrameworkKeyword:
Douglas Gregora30cfe52011-11-11 19:10:28 +0000773 parseModuleDecl();
774 break;
775
776 case MMToken::ExplicitKeyword:
Douglas Gregor90db2602011-12-02 01:47:07 +0000777 case MMToken::ExportKeyword:
Douglas Gregora30cfe52011-11-11 19:10:28 +0000778 case MMToken::HeaderKeyword:
779 case MMToken::Identifier:
780 case MMToken::LBrace:
Douglas Gregor90db2602011-12-02 01:47:07 +0000781 case MMToken::Period:
Douglas Gregora30cfe52011-11-11 19:10:28 +0000782 case MMToken::RBrace:
Douglas Gregor90db2602011-12-02 01:47:07 +0000783 case MMToken::Star:
Douglas Gregora30cfe52011-11-11 19:10:28 +0000784 case MMToken::StringLiteral:
785 case MMToken::UmbrellaKeyword:
786 Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
787 HadError = true;
788 consumeToken();
789 break;
790 }
791 } while (true);
792
793 return HadError;
794}
795
796bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
797 FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
798 const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
799 if (!Buffer)
800 return true;
801
802 // Parse this module map file.
803 Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, LangOpts);
804 Diags->getClient()->BeginSourceFile(LangOpts);
Douglas Gregor8b6d3de2011-11-11 21:55:48 +0000805 ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir());
Douglas Gregora30cfe52011-11-11 19:10:28 +0000806 bool Result = Parser.parseModuleMapFile();
807 Diags->getClient()->EndSourceFile();
808
809 return Result;
810}