aboutsummaryrefslogtreecommitdiff
path: root/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Lex/ModuleMap.cpp')
-rw-r--r--lib/Lex/ModuleMap.cpp122
1 files changed, 92 insertions, 30 deletions
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 164eb27e72..498061fc05 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -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;
}
@@ -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)
@@ -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)
@@ -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)