2011-11-12 03:10:28 +08:00
|
|
|
//===--- ModuleMap.cpp - Describe the layout of modules ---------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the ModuleMap implementation, which describes the layout
|
|
|
|
// of a module as it relates to headers.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Lex/ModuleMap.h"
|
|
|
|
#include "clang/Lex/Lexer.h"
|
|
|
|
#include "clang/Lex/LiteralSupport.h"
|
|
|
|
#include "clang/Lex/LexDiagnostic.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Basic/TargetOptions.h"
|
|
|
|
#include "llvm/Support/Allocator.h"
|
|
|
|
#include "llvm/Support/Host.h"
|
2011-11-12 05:55:48 +08:00
|
|
|
#include "llvm/Support/PathV2.h"
|
2011-11-12 03:10:28 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Module
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
std::string ModuleMap::Module::getFullModuleName() const {
|
|
|
|
llvm::SmallVector<StringRef, 2> Names;
|
|
|
|
|
|
|
|
// Build up the set of module names (from innermost to outermost).
|
|
|
|
for (const Module *M = this; M; M = M->Parent)
|
|
|
|
Names.push_back(M->Name);
|
|
|
|
|
|
|
|
std::string Result;
|
|
|
|
for (llvm::SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
|
|
|
|
IEnd = Names.rend();
|
|
|
|
I != IEnd; ++I) {
|
|
|
|
if (!Result.empty())
|
|
|
|
Result += '.';
|
|
|
|
|
|
|
|
Result += *I;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2011-11-12 06:18:48 +08:00
|
|
|
StringRef ModuleMap::Module::getTopLevelModuleName() const {
|
|
|
|
const Module *Top = this;
|
|
|
|
while (Top->Parent)
|
|
|
|
Top = Top->Parent;
|
|
|
|
|
|
|
|
return Top->Name;
|
|
|
|
}
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Module map
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC) {
|
|
|
|
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
|
|
|
|
Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
|
|
|
|
new DiagnosticsEngine(DiagIDs));
|
|
|
|
Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true);
|
|
|
|
SourceMgr = new SourceManager(*Diags, FileMgr);
|
|
|
|
}
|
|
|
|
|
|
|
|
ModuleMap::~ModuleMap() {
|
|
|
|
delete SourceMgr;
|
|
|
|
}
|
|
|
|
|
2011-11-12 06:18:48 +08:00
|
|
|
ModuleMap::Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
|
|
|
|
llvm::DenseMap<const FileEntry *, Module *>::iterator Known
|
|
|
|
= Headers.find(File);
|
|
|
|
if (Known != Headers.end())
|
|
|
|
return Known->second;
|
|
|
|
|
2011-11-17 07:02:25 +08:00
|
|
|
const DirectoryEntry *Dir = File->getDir();
|
|
|
|
llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
|
|
|
|
= UmbrellaDirs.find(Dir);
|
|
|
|
if (KnownDir != UmbrellaDirs.end())
|
|
|
|
return KnownDir->second;
|
|
|
|
|
|
|
|
// Walk up the directory hierarchy looking for umbrella headers.
|
|
|
|
llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
|
|
|
|
StringRef DirName = Dir->getName();
|
|
|
|
do {
|
|
|
|
// Retrieve our parent path.
|
|
|
|
DirName = llvm::sys::path::parent_path(DirName);
|
|
|
|
if (DirName.empty())
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Resolve the parent path to a directory entry.
|
|
|
|
Dir = SourceMgr->getFileManager().getDirectory(DirName);
|
|
|
|
if (!Dir)
|
|
|
|
break;
|
|
|
|
|
|
|
|
KnownDir = UmbrellaDirs.find(Dir);
|
|
|
|
if (KnownDir != UmbrellaDirs.end()) {
|
|
|
|
Module *Result = KnownDir->second;
|
|
|
|
|
|
|
|
// Record each of the directories we stepped through as being part of
|
|
|
|
// the module we found, since the umbrella header covers them all.
|
|
|
|
for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
|
|
|
|
UmbrellaDirs[SkippedDirs[I]] = Result;
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkippedDirs.push_back(Dir);
|
|
|
|
} while (true);
|
|
|
|
|
2011-11-12 06:18:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-12 07:20:24 +08:00
|
|
|
ModuleMap::Module *ModuleMap::findModule(StringRef Name) {
|
|
|
|
llvm::StringMap<Module *>::iterator Known = Modules.find(Name);
|
|
|
|
if (Known != Modules.end())
|
|
|
|
return Known->getValue();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
static void indent(llvm::raw_ostream &OS, unsigned Spaces) {
|
|
|
|
OS << std::string(' ', Spaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dumpModule(llvm::raw_ostream &OS, ModuleMap::Module *M,
|
|
|
|
unsigned Indent) {
|
|
|
|
indent(OS, Indent);
|
|
|
|
if (M->IsExplicit)
|
|
|
|
OS << "explicit ";
|
|
|
|
OS << M->Name << " {\n";
|
|
|
|
|
|
|
|
if (M->UmbrellaHeader) {
|
|
|
|
indent(OS, Indent + 2);
|
|
|
|
OS << "umbrella \"" << M->UmbrellaHeader->getName() << "\"\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = M->Headers.size(); I != N; ++I) {
|
|
|
|
indent(OS, Indent + 2);
|
|
|
|
OS << "header \"" << M->Headers[I]->getName() << "\"\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (llvm::StringMap<ModuleMap::Module *>::iterator
|
|
|
|
MI = M->SubModules.begin(),
|
|
|
|
MIEnd = M->SubModules.end();
|
|
|
|
MI != MIEnd; ++MI)
|
|
|
|
dumpModule(llvm::errs(), MI->getValue(), Indent + 2);
|
|
|
|
|
|
|
|
indent(OS, Indent);
|
|
|
|
OS << "}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleMap::dump() {
|
|
|
|
llvm::errs() << "Modules:";
|
|
|
|
for (llvm::StringMap<Module *>::iterator M = Modules.begin(),
|
|
|
|
MEnd = Modules.end();
|
|
|
|
M != MEnd; ++M)
|
|
|
|
dumpModule(llvm::errs(), M->getValue(), 2);
|
|
|
|
|
|
|
|
llvm::errs() << "Headers:";
|
|
|
|
for (llvm::DenseMap<const FileEntry *, Module *>::iterator
|
|
|
|
H = Headers.begin(),
|
|
|
|
HEnd = Headers.end();
|
|
|
|
H != HEnd; ++H) {
|
|
|
|
llvm::errs() << " \"" << H->first->getName() << "\" -> "
|
|
|
|
<< H->second->getFullModuleName() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Module map file parser
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
/// \brief A token in a module map file.
|
|
|
|
struct MMToken {
|
|
|
|
enum TokenKind {
|
|
|
|
EndOfFile,
|
|
|
|
HeaderKeyword,
|
|
|
|
Identifier,
|
|
|
|
ExplicitKeyword,
|
|
|
|
ModuleKeyword,
|
|
|
|
UmbrellaKeyword,
|
|
|
|
StringLiteral,
|
|
|
|
LBrace,
|
|
|
|
RBrace
|
|
|
|
} Kind;
|
|
|
|
|
|
|
|
unsigned Location;
|
|
|
|
unsigned StringLength;
|
|
|
|
const char *StringData;
|
|
|
|
|
|
|
|
void clear() {
|
|
|
|
Kind = EndOfFile;
|
|
|
|
Location = 0;
|
|
|
|
StringLength = 0;
|
|
|
|
StringData = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is(TokenKind K) const { return Kind == K; }
|
|
|
|
|
|
|
|
SourceLocation getLocation() const {
|
|
|
|
return SourceLocation::getFromRawEncoding(Location);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getString() const {
|
|
|
|
return StringRef(StringData, StringLength);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ModuleMapParser {
|
|
|
|
Lexer &L;
|
|
|
|
SourceManager &SourceMgr;
|
|
|
|
DiagnosticsEngine &Diags;
|
|
|
|
ModuleMap ⤅
|
|
|
|
|
2011-11-12 05:55:48 +08:00
|
|
|
/// \brief The directory that this module map resides in.
|
|
|
|
const DirectoryEntry *Directory;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
/// \brief Whether an error occurred.
|
|
|
|
bool HadError;
|
|
|
|
|
|
|
|
/// \brief Default target information, used only for string literal
|
|
|
|
/// parsing.
|
|
|
|
TargetInfo *Target;
|
|
|
|
|
|
|
|
/// \brief Stores string data for the various string literals referenced
|
|
|
|
/// during parsing.
|
|
|
|
llvm::BumpPtrAllocator StringData;
|
|
|
|
|
|
|
|
/// \brief The current token.
|
|
|
|
MMToken Tok;
|
|
|
|
|
|
|
|
/// \brief The active module.
|
|
|
|
ModuleMap::Module *ActiveModule;
|
|
|
|
|
|
|
|
/// \brief Consume the current token and return its location.
|
|
|
|
SourceLocation consumeToken();
|
|
|
|
|
|
|
|
/// \brief Skip tokens until we reach the a token with the given kind
|
|
|
|
/// (or the end of the file).
|
|
|
|
void skipUntil(MMToken::TokenKind K);
|
|
|
|
|
|
|
|
void parseModuleDecl();
|
|
|
|
void parseUmbrellaDecl();
|
|
|
|
void parseHeaderDecl();
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef ModuleMap::Module Module;
|
|
|
|
|
|
|
|
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
|
|
|
|
DiagnosticsEngine &Diags,
|
2011-11-12 05:55:48 +08:00
|
|
|
ModuleMap &Map,
|
|
|
|
const DirectoryEntry *Directory)
|
|
|
|
: L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map),
|
|
|
|
Directory(Directory), HadError(false), ActiveModule(0)
|
2011-11-12 03:10:28 +08:00
|
|
|
{
|
|
|
|
TargetOptions TargetOpts;
|
|
|
|
TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
|
|
|
|
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
|
|
|
|
|
|
|
|
Tok.clear();
|
|
|
|
consumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parseModuleMapFile();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation ModuleMapParser::consumeToken() {
|
|
|
|
retry:
|
|
|
|
SourceLocation Result = Tok.getLocation();
|
|
|
|
Tok.clear();
|
|
|
|
|
|
|
|
Token LToken;
|
|
|
|
L.LexFromRawLexer(LToken);
|
|
|
|
Tok.Location = LToken.getLocation().getRawEncoding();
|
|
|
|
switch (LToken.getKind()) {
|
|
|
|
case tok::raw_identifier:
|
|
|
|
Tok.StringData = LToken.getRawIdentifierData();
|
|
|
|
Tok.StringLength = LToken.getLength();
|
|
|
|
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
|
|
|
|
.Case("header", MMToken::HeaderKeyword)
|
|
|
|
.Case("explicit", MMToken::ExplicitKeyword)
|
|
|
|
.Case("module", MMToken::ModuleKeyword)
|
|
|
|
.Case("umbrella", MMToken::UmbrellaKeyword)
|
|
|
|
.Default(MMToken::Identifier);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::eof:
|
|
|
|
Tok.Kind = MMToken::EndOfFile;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::l_brace:
|
|
|
|
Tok.Kind = MMToken::LBrace;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::r_brace:
|
|
|
|
Tok.Kind = MMToken::RBrace;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::string_literal: {
|
|
|
|
// Parse the string literal.
|
|
|
|
LangOptions LangOpts;
|
|
|
|
StringLiteralParser StringLiteral(<oken, 1, SourceMgr, LangOpts, *Target);
|
|
|
|
if (StringLiteral.hadError)
|
|
|
|
goto retry;
|
|
|
|
|
|
|
|
// Copy the string literal into our string data allocator.
|
|
|
|
unsigned Length = StringLiteral.GetStringLength();
|
|
|
|
char *Saved = StringData.Allocate<char>(Length + 1);
|
|
|
|
memcpy(Saved, StringLiteral.GetString().data(), Length);
|
|
|
|
Saved[Length] = 0;
|
|
|
|
|
|
|
|
// Form the token.
|
|
|
|
Tok.Kind = MMToken::StringLiteral;
|
|
|
|
Tok.StringData = Saved;
|
|
|
|
Tok.StringLength = Length;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case tok::comment:
|
|
|
|
goto retry;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Diags.Report(LToken.getLocation(), diag::err_mmap_unknown_token);
|
|
|
|
HadError = true;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
|
|
|
|
unsigned braceDepth = 0;
|
|
|
|
do {
|
|
|
|
switch (Tok.Kind) {
|
|
|
|
case MMToken::EndOfFile:
|
|
|
|
return;
|
|
|
|
|
|
|
|
case MMToken::LBrace:
|
|
|
|
if (Tok.is(K) && braceDepth == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
++braceDepth;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MMToken::RBrace:
|
|
|
|
if (braceDepth > 0)
|
|
|
|
--braceDepth;
|
|
|
|
else if (Tok.is(K))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (braceDepth == 0 && Tok.is(K))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
consumeToken();
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse a module declaration.
|
|
|
|
///
|
|
|
|
/// module-declaration:
|
|
|
|
/// 'module' identifier { module-member* }
|
|
|
|
///
|
|
|
|
/// module-member:
|
|
|
|
/// umbrella-declaration
|
|
|
|
/// header-declaration
|
|
|
|
/// 'explicit'[opt] module-declaration
|
|
|
|
void ModuleMapParser::parseModuleDecl() {
|
|
|
|
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword));
|
|
|
|
|
|
|
|
// Parse 'explicit' keyword, if present.
|
|
|
|
bool Explicit = false;
|
|
|
|
if (Tok.is(MMToken::ExplicitKeyword)) {
|
|
|
|
consumeToken();
|
|
|
|
Explicit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse 'module' keyword.
|
|
|
|
if (!Tok.is(MMToken::ModuleKeyword)) {
|
|
|
|
Diags.Report(Tok.getLocation(),
|
|
|
|
diag::err_mmap_expected_module_after_explicit);
|
|
|
|
consumeToken();
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
consumeToken(); // 'module' keyword
|
|
|
|
|
|
|
|
// Parse the module name.
|
|
|
|
if (!Tok.is(MMToken::Identifier)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
StringRef ModuleName = Tok.getString();
|
|
|
|
SourceLocation ModuleNameLoc = consumeToken();
|
|
|
|
|
|
|
|
// Parse the opening brace.
|
|
|
|
if (!Tok.is(MMToken::LBrace)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
|
|
|
|
<< ModuleName;
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SourceLocation LBraceLoc = consumeToken();
|
|
|
|
|
|
|
|
// Determine whether this (sub)module has already been defined.
|
|
|
|
llvm::StringMap<Module *> &ModuleSpace
|
|
|
|
= ActiveModule? ActiveModule->SubModules : Map.Modules;
|
|
|
|
llvm::StringMap<Module *>::iterator ExistingModule
|
|
|
|
= ModuleSpace.find(ModuleName);
|
|
|
|
if (ExistingModule != ModuleSpace.end()) {
|
|
|
|
Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
|
|
|
|
<< ModuleName;
|
|
|
|
Diags.Report(ExistingModule->getValue()->DefinitionLoc,
|
|
|
|
diag::note_mmap_prev_definition);
|
|
|
|
|
|
|
|
// Skip the module definition.
|
|
|
|
skipUntil(MMToken::RBrace);
|
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start defining this module.
|
|
|
|
ActiveModule = new Module(ModuleName, ModuleNameLoc, ActiveModule, Explicit);
|
|
|
|
ModuleSpace[ModuleName] = ActiveModule;
|
|
|
|
|
|
|
|
bool Done = false;
|
|
|
|
do {
|
|
|
|
switch (Tok.Kind) {
|
|
|
|
case MMToken::EndOfFile:
|
|
|
|
case MMToken::RBrace:
|
|
|
|
Done = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MMToken::ExplicitKeyword:
|
|
|
|
case MMToken::ModuleKeyword:
|
|
|
|
parseModuleDecl();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MMToken::HeaderKeyword:
|
|
|
|
parseHeaderDecl();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MMToken::UmbrellaKeyword:
|
|
|
|
parseUmbrellaDecl();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
|
|
|
|
consumeToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!Done);
|
|
|
|
|
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
else {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
|
|
|
|
Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
|
|
|
|
HadError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're done parsing this module. Pop back to our parent scope.
|
|
|
|
ActiveModule = ActiveModule->Parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse an umbrella header declaration.
|
|
|
|
///
|
|
|
|
/// umbrella-declaration:
|
|
|
|
/// 'umbrella' string-literal
|
|
|
|
void ModuleMapParser::parseUmbrellaDecl() {
|
|
|
|
assert(Tok.is(MMToken::UmbrellaKeyword));
|
|
|
|
SourceLocation UmbrellaLoc = consumeToken();
|
|
|
|
|
|
|
|
// Parse the header name.
|
|
|
|
if (!Tok.is(MMToken::StringLiteral)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
|
|
|
|
<< "umbrella";
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
StringRef FileName = Tok.getString();
|
|
|
|
SourceLocation FileNameLoc = consumeToken();
|
|
|
|
|
2011-11-12 05:55:48 +08:00
|
|
|
// Check whether we already have an umbrella header.
|
|
|
|
if (ActiveModule->UmbrellaHeader) {
|
|
|
|
Diags.Report(FileNameLoc, diag::err_mmap_umbrella_header_conflict)
|
|
|
|
<< ActiveModule->getFullModuleName()
|
|
|
|
<< ActiveModule->UmbrellaHeader->getName();
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only top-level modules can have umbrella headers.
|
|
|
|
if (ActiveModule->Parent) {
|
|
|
|
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_header_submodule)
|
|
|
|
<< ActiveModule->getFullModuleName();
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look for this file.
|
|
|
|
llvm::SmallString<128> PathName;
|
|
|
|
PathName += Directory->getName();
|
|
|
|
llvm::sys::path::append(PathName, FileName);
|
|
|
|
|
|
|
|
// FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
|
|
|
|
// Come up with a lazy way to do this.
|
|
|
|
if (const FileEntry *File = SourceMgr.getFileManager().getFile(PathName)) {
|
|
|
|
if (const Module *OwningModule = Map.Headers[File]) {
|
|
|
|
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
|
|
|
|
<< FileName << OwningModule->getFullModuleName();
|
|
|
|
HadError = true;
|
2011-11-17 07:02:25 +08:00
|
|
|
} else if ((OwningModule = Map.UmbrellaDirs[Directory])) {
|
|
|
|
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
|
|
|
|
<< OwningModule->getFullModuleName();
|
|
|
|
HadError = true;
|
2011-11-12 05:55:48 +08:00
|
|
|
} else {
|
|
|
|
// Record this umbrella header.
|
|
|
|
ActiveModule->UmbrellaHeader = File;
|
|
|
|
Map.Headers[File] = ActiveModule;
|
2011-11-17 07:02:25 +08:00
|
|
|
Map.UmbrellaDirs[Directory] = ActiveModule;
|
2011-11-12 05:55:48 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
|
|
|
|
<< true << FileName;
|
|
|
|
HadError = true;
|
|
|
|
}
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse a header declaration.
|
|
|
|
///
|
|
|
|
/// header-declaration:
|
|
|
|
/// 'header' string-literal
|
|
|
|
void ModuleMapParser::parseHeaderDecl() {
|
|
|
|
assert(Tok.is(MMToken::HeaderKeyword));
|
2011-11-14 00:52:09 +08:00
|
|
|
consumeToken();
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Parse the header name.
|
|
|
|
if (!Tok.is(MMToken::StringLiteral)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
|
|
|
|
<< "header";
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
StringRef FileName = Tok.getString();
|
|
|
|
SourceLocation FileNameLoc = consumeToken();
|
|
|
|
|
2011-11-12 05:55:48 +08:00
|
|
|
// Look for this file.
|
|
|
|
llvm::SmallString<128> PathName;
|
|
|
|
PathName += Directory->getName();
|
|
|
|
llvm::sys::path::append(PathName, FileName);
|
|
|
|
|
|
|
|
// FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
|
|
|
|
// Come up with a lazy way to do this.
|
|
|
|
if (const FileEntry *File = SourceMgr.getFileManager().getFile(PathName)) {
|
|
|
|
if (const Module *OwningModule = Map.Headers[File]) {
|
|
|
|
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
|
|
|
|
<< FileName << OwningModule->getFullModuleName();
|
|
|
|
HadError = true;
|
|
|
|
} else {
|
|
|
|
// Record this file.
|
|
|
|
ActiveModule->Headers.push_back(File);
|
|
|
|
Map.Headers[File] = ActiveModule;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
|
|
|
|
<< false << FileName;
|
|
|
|
HadError = true;
|
|
|
|
}
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse a module map file.
|
|
|
|
///
|
|
|
|
/// module-map-file:
|
|
|
|
/// module-declaration*
|
|
|
|
bool ModuleMapParser::parseModuleMapFile() {
|
|
|
|
do {
|
|
|
|
switch (Tok.Kind) {
|
|
|
|
case MMToken::EndOfFile:
|
|
|
|
return HadError;
|
|
|
|
|
|
|
|
case MMToken::ModuleKeyword:
|
|
|
|
parseModuleDecl();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MMToken::ExplicitKeyword:
|
|
|
|
case MMToken::HeaderKeyword:
|
|
|
|
case MMToken::Identifier:
|
|
|
|
case MMToken::LBrace:
|
|
|
|
case MMToken::RBrace:
|
|
|
|
case MMToken::StringLiteral:
|
|
|
|
case MMToken::UmbrellaKeyword:
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
|
|
|
|
HadError = true;
|
|
|
|
consumeToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
return HadError;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
|
|
|
|
FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
|
|
|
|
const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
|
|
|
|
if (!Buffer)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Parse this module map file.
|
|
|
|
Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, LangOpts);
|
|
|
|
Diags->getClient()->BeginSourceFile(LangOpts);
|
2011-11-12 05:55:48 +08:00
|
|
|
ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir());
|
2011-11-12 03:10:28 +08:00
|
|
|
bool Result = Parser.parseModuleMapFile();
|
|
|
|
Diags->getClient()->EndSourceFile();
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|