diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-12-06 01:10:29 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-12-06 01:10:29 +0000 |
commit | e209e5026892cb07294f733c72bd51359c0f0e72 (patch) | |
tree | ba7b04ead00a1068a2ff130d38cc6b4b24a48d53 /lib/Lex/ModuleMap.cpp | |
parent | 19efa3ee5a7f2232884f9cca6871329ffe85653c (diff) |
Implement inferred submodules support, which (when requested)
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
Diffstat (limited to 'lib/Lex/ModuleMap.cpp')
-rw-r--r-- | lib/Lex/ModuleMap.cpp | 122 |
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) |