Skip to content

Commit

Permalink
Implement inferred submodules support, which (when requested)
Browse files Browse the repository at this point in the history
implicitly generates submodules corresponding to the headers that fall
within a module.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145887 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
DougGregor committed Dec 6, 2011
1 parent 19efa3e commit e209e50
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 59 deletions.
7 changes: 7 additions & 0 deletions include/clang/Lex/ModuleMap.h
Expand Up @@ -177,6 +177,13 @@ class ModuleMap {
/// module owns this source location.
Module *inferModuleFromLocation(FullSourceLoc Loc);

/// \brief Sets the umbrella header of the given module to the given
/// header.
void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader);

/// \brief Adds this header to the given module.
void addHeader(Module *Mod, const FileEntry *Header);

/// \brief Parse the given module map file, and record any modules we
/// encounter.
///
Expand Down
6 changes: 6 additions & 0 deletions include/clang/Serialization/ASTWriter.h
Expand Up @@ -101,6 +101,9 @@ class ASTWriter : public ASTDeserializationListener,
/// \brief The reader of existing AST files, if we're chaining.
ASTReader *Chain;

/// \brief The module we're currently writing, if any.
Module *WritingModule;

/// \brief Indicates when the AST writing is actively performing
/// serialization, rather than just queueing updates.
bool WritingAST;
Expand Down Expand Up @@ -368,6 +371,9 @@ class ASTWriter : public ASTDeserializationListener,
/// be a positive integer.
llvm::DenseMap<Module *, unsigned> SubmoduleIDs;

/// \brief Retrieve or create a submodule ID for this module.
unsigned getSubmoduleID(Module *Mod);

/// \brief Write the given subexpression to the bitstream.
void WriteSubStmt(Stmt *S,
llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,
Expand Down
122 changes: 92 additions & 30 deletions lib/Lex/ModuleMap.cpp
Expand Up @@ -93,39 +93,75 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
return Known->second;

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);

// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
do {
llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
= UmbrellaDirs.find(Dir);
if (KnownDir != UmbrellaDirs.end()) {
Module *Result = KnownDir->second;
Module *TopModule = Result->getTopLevelModule();
if (TopModule->InferSubmodules) {
// Infer submodules for each of the directories we found between
// the directory of the umbrella header and the directory where
// the actual header is located.

// For a framework module, the umbrella directory is the framework
// directory, so strip off the "Headers" or "PrivateHeaders".
// FIXME: Should we tack on an "explicit" for PrivateHeaders? That
// might be what we want, but it feels like a hack.
unsigned LastSkippedDir = SkippedDirs.size();
if (LastSkippedDir && TopModule->IsFramework)
--LastSkippedDir;

for (unsigned I = LastSkippedDir; I != 0; --I) {
// Find or create the module that corresponds to this directory name.
StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
TopModule->InferExplicitSubmodules).first;

// Associate the module and the directory.
UmbrellaDirs[SkippedDirs[I-1]] = Result;

// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
if (TopModule->InferExportWildcard && Result->Exports.empty())
Result->Exports.push_back(Module::ExportDecl(0, true));
}

// Infer a submodule with the same name as this header file.
StringRef Name = llvm::sys::path::stem(File->getName());
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
TopModule->InferExplicitSubmodules).first;

// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
if (TopModule->InferExportWildcard && Result->Exports.empty())
Result->Exports.push_back(Module::ExportDecl(0, true));
} else {
// 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;
}

// 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;

Headers[File] = Result;
return Result;
}

SkippedDirs.push_back(Dir);
} while (true);

// 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);
} while (Dir);

return 0;
}
Expand Down Expand Up @@ -205,10 +241,31 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// export *
Result->Exports.push_back(Module::ExportDecl(0, true));

// module * { export * }
Result->InferSubmodules = true;
Result->InferExportWildcard = true;

Modules[ModuleName] = Result;
return Result;
}

void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
Headers[UmbrellaHeader] = Mod;
Mod->UmbrellaHeader = UmbrellaHeader;

const DirectoryEntry *UmbrellaDir = UmbrellaHeader->getDir();
if (Mod->IsFramework)
UmbrellaDir = SourceMgr->getFileManager().getDirectory(
llvm::sys::path::parent_path(UmbrellaDir->getName()));

UmbrellaDirs[UmbrellaDir] = Mod;
}

void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) {
Mod->Headers.push_back(Header);
Headers[Header] = Mod;
}

const FileEntry *
ModuleMap::getContainingModuleMapFile(Module *Module) {
if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
Expand Down Expand Up @@ -683,19 +740,25 @@ void ModuleMapParser::parseUmbrellaDecl() {
// 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 (File) {
const DirectoryEntry *UmbrellaDir = File->getDir();
if (ActiveModule->IsFramework) {
// For framework modules, use the framework directory as the umbrella
// directory.
UmbrellaDir = SourceMgr.getFileManager().getDirectory(
llvm::sys::path::parent_path(UmbrellaDir->getName()));
}

if (const Module *OwningModule = Map.Headers[File]) {
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
<< FileName << OwningModule->getFullModuleName();
HadError = true;
} else if ((OwningModule = Map.UmbrellaDirs[Directory])) {
} else if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
<< OwningModule->getFullModuleName();
HadError = true;
} else {
// Record this umbrella header.
ActiveModule->UmbrellaHeader = File;
Map.Headers[File] = ActiveModule;
Map.UmbrellaDirs[Directory] = ActiveModule;
Map.setUmbrellaHeader(ActiveModule, File);
}
} else {
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
Expand Down Expand Up @@ -743,8 +806,7 @@ void ModuleMapParser::parseHeaderDecl() {
HadError = true;
} else {
// Record this file.
ActiveModule->Headers.push_back(File);
Map.Headers[File] = ActiveModule;
Map.addHeader(ActiveModule, File);
}
} else {
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
Expand Down
31 changes: 15 additions & 16 deletions lib/Serialization/ASTReader.cpp
Expand Up @@ -3049,18 +3049,19 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
return Failure;
}

if (Record.size() < 6) {
if (Record.size() < 7) {
Error("malformed module definition");
return Failure;
}

StringRef Name(BlobStart, BlobLen);
unsigned Parent = getGlobalSubmoduleID(F, Record[0]);
bool IsFramework = Record[1];
bool IsExplicit = Record[2];
bool InferSubmodules = Record[3];
bool InferExplicitSubmodules = Record[4];
bool InferExportWildcard = Record[5];
SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
bool IsFramework = Record[2];
bool IsExplicit = Record[3];
bool InferSubmodules = Record[4];
bool InferExplicitSubmodules = Record[5];
bool InferExportWildcard = Record[6];

Module *ParentModule = 0;
if (Parent)
Expand All @@ -3071,9 +3072,9 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
IsFramework,
IsExplicit).first;

if (CurrentModuleGlobalIndex >= SubmodulesLoaded.size() ||
SubmodulesLoaded[CurrentModuleGlobalIndex]) {
SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
if (GlobalIndex >= SubmodulesLoaded.size() ||
SubmodulesLoaded[GlobalIndex]) {
Error("too many submodules");
return Failure;
}
Expand All @@ -3082,11 +3083,9 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
if (DeserializationListener)
DeserializationListener->ModuleRead(
CurrentModuleGlobalIndex + NUM_PREDEF_SUBMODULE_IDS,
CurrentModule);
DeserializationListener->ModuleRead(GlobalID, CurrentModule);

SubmodulesLoaded[CurrentModuleGlobalIndex++] = CurrentModule;
SubmodulesLoaded[GlobalIndex] = CurrentModule;
break;
}

Expand All @@ -3102,7 +3101,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
StringRef FileName(BlobStart, BlobLen);
if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
if (!CurrentModule->UmbrellaHeader)
CurrentModule->UmbrellaHeader = Umbrella;
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
else if (CurrentModule->UmbrellaHeader != Umbrella) {
Error("mismatched umbrella headers in submodule");
return Failure;
Expand All @@ -3126,7 +3125,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (std::find(CurrentModule->Headers.begin(),
CurrentModule->Headers.end(),
File) == CurrentModule->Headers.end())
CurrentModule->Headers.push_back(File);
ModMap.addHeader(CurrentModule, File);
}
break;
}
Expand Down
39 changes: 26 additions & 13 deletions lib/Serialization/ASTWriter.cpp
Expand Up @@ -1845,6 +1845,14 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
}
}

unsigned ASTWriter::getSubmoduleID(Module *Mod) {
llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod);
if (Known != SubmoduleIDs.end())
return Known->second;

return SubmoduleIDs[Mod] = NextSubmoduleID++;
}

/// \brief Compute the number of modules within the given tree (including the
/// given module).
static unsigned getNumberOfModules(Module *Mod) {
Expand Down Expand Up @@ -1881,6 +1889,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
Expand Down Expand Up @@ -1912,12 +1921,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
while (!Q.empty()) {
Module *Mod = Q.front();
Q.pop();
assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
SubmoduleIDs[Mod] = NextSubmoduleID++;
unsigned ID = getSubmoduleID(Mod);

// Emit the definition of the block.
Record.clear();
Record.push_back(SUBMODULE_DEFINITION);
Record.push_back(ID);
if (Mod->Parent) {
assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
Record.push_back(SubmoduleIDs[Mod->Parent]);
Expand Down Expand Up @@ -1988,11 +1997,14 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
}

Stream.ExitBlock();

assert((NextSubmoduleID - FirstSubmoduleID
== getNumberOfModules(WritingModule)) && "Wrong # of submodules");
}

serialization::SubmoduleID
ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
if (Loc.isInvalid() || SubmoduleIDs.empty())
if (Loc.isInvalid() || !WritingModule)
return 0; // No submodule

// Find the module that owns this location.
Expand All @@ -2002,13 +2014,11 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
if (!OwningMod)
return 0;

// Check whether we known about this submodule.
llvm::DenseMap<Module *, unsigned>::iterator Known
= SubmoduleIDs.find(OwningMod);
if (Known == SubmoduleIDs.end())
// Check whether this submodule is part of our own module.
if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule))
return 0;

return Known->second;
return getSubmoduleID(OwningMod);
}

void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
Expand Down Expand Up @@ -2933,7 +2943,8 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}

ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
: Stream(Stream), Context(0), PP(0), Chain(0), WritingAST(false),
: Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0),
WritingAST(false),
FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
Expand Down Expand Up @@ -2975,9 +2986,11 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,

Context = &SemaRef.Context;
PP = &SemaRef.PP;
this->WritingModule = WritingModule;
WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule);
Context = 0;
PP = 0;
this->WritingModule = 0;

WritingAST = false;
}
Expand Down Expand Up @@ -3201,10 +3214,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
AddTypeRef(Context.getucontext_tType(), SpecialTypes);

// If we're emitting a module, write out the submodule information.
if (WritingModule)
WriteSubmodules(WritingModule);

// Keep writing types and declarations until all types and
// declarations have been written.
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
Expand Down Expand Up @@ -3282,6 +3291,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,

WriteCXXBaseSpecifiersOffsets();

// If we're emitting a module, write out the submodule information.
if (WritingModule)
WriteSubmodules(WritingModule);

Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);

/// Build a record containing first declarations from a chained PCH and the
Expand Down
@@ -0,0 +1 @@
unsigned *Buried_Treasure;

0 comments on commit e209e50

Please sign in to comment.