When building a module from a module map that isn't simply an umbrella
header, create our own in-memory buffer to parse all of the
appropriate headers, and use that to build the module. This isn't
end-to-end testable yet; that's coming next.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144797 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 167d070..f48e9e3 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -178,4 +178,6 @@
DefaultFatal;
def err_missing_module : Error<
"no module named '%0' declared in module map file '%1'">, DefaultFatal;
+def err_missing_umbrella_header : Error<
+ "cannot open umbrella header '%0': %1">, DefaultFatal;
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 243f527..8e2e215 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -126,6 +126,38 @@
Sysroot, OS);
}
+/// \brief Collect the set of header includes needed to construct the given
+/// module.
+///
+/// \param Module The module we're collecting includes from.
+/// \param ExplicitOnly Whether we should only add headers from explicit
+static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
+ ModuleMap::Module *Module,
+ bool ExplicitOnly,
+ llvm::SmallString<256> &Includes) {
+ if (!ExplicitOnly || Module->IsExplicit) {
+ // Add includes for each of these headers.
+ for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+ Includes += Module->Headers[I]->getName();
+ Includes += "\"\n";
+ }
+ }
+
+ // Recurse into submodules.
+ for (llvm::StringMap<ModuleMap::Module *>::iterator
+ Sub = Module->SubModules.begin(),
+ SubEnd = Module->SubModules.end();
+ Sub != SubEnd; ++Sub) {
+ collectModuleHeaderIncludes(LangOpts, Sub->getValue(),
+ ExplicitOnly && !Module->IsExplicit,
+ Includes);
+ }
+}
+
bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) {
// Find the module map file.
@@ -161,18 +193,72 @@
return false;
}
- // If there is an umbrella header, use it as our actual input file.
- if (Module->UmbrellaHeader) {
- // FIXME: Deal with explicit submodule headers, which won't be contained
- // within the umbrella header.
+ // Collect the set of #includes we need to build the module.
+ llvm::SmallString<256> HeaderContents;
+ collectModuleHeaderIncludes(CI.getLangOpts(), Module,
+ Module->UmbrellaHeader != 0, HeaderContents);
+ if (Module->UmbrellaHeader && HeaderContents.empty()) {
+ // Simple case: we have an umbrella header and there are no additional
+ // includes, we can just parse the umbrella header directly.
setCurrentFile(Module->UmbrellaHeader->getName(), getCurrentFileKind());
- } else {
- // FIXME: Deal with the non-umbrella case, where we have to synthesize
- // a header to parse.
- // FIXME: Diagnose, at least for now.
- return false;
+ return true;
}
+ FileManager &FileMgr = CI.getFileManager();
+ llvm::SmallString<128> HeaderName;
+ time_t ModTime;
+ if (Module->UmbrellaHeader) {
+ // Read in the umbrella header.
+ // FIXME: Go through the source manager; the umbrella header may have
+ // been overridden.
+ std::string ErrorStr;
+ llvm::MemoryBuffer *UmbrellaContents
+ = FileMgr.getBufferForFile(Module->UmbrellaHeader, &ErrorStr);
+ if (!UmbrellaContents) {
+ CI.getDiagnostics().Report(diag::err_missing_umbrella_header)
+ << Module->UmbrellaHeader->getName() << ErrorStr;
+ return false;
+ }
+
+ // Combine the contents of the umbrella header with the automatically-
+ // generated includes.
+ llvm::SmallString<256> OldContents = HeaderContents;
+ HeaderContents = UmbrellaContents->getBuffer();
+ HeaderContents += "\n\n";
+ HeaderContents += "/* Module includes */\n";
+ HeaderContents += OldContents;
+
+ // Pretend that we're parsing the umbrella header.
+ HeaderName = Module->UmbrellaHeader->getName();
+ ModTime = Module->UmbrellaHeader->getModificationTime();
+
+ delete UmbrellaContents;
+ } else {
+ // Pick an innocuous-sounding name for the umbrella header.
+ HeaderName = Module->Name + ".h";
+ if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
+ /*CacheFailure=*/false)) {
+ // Try again!
+ HeaderName = Module->Name + "-module.h";
+ if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
+ /*CacheFailure=*/false)) {
+ // Pick something ridiculous and go with it.
+ HeaderName = Module->Name + "-module.hmod";
+ }
+ }
+ ModTime = time(0);
+ }
+
+ // Remap the contents of the header name we're using to our synthesized
+ // buffer.
+ const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName,
+ HeaderContents.size(),
+ ModTime);
+ llvm::MemoryBuffer *HeaderContentsBuf
+ = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
+ CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
+
+ setCurrentFile(HeaderName, getCurrentFileKind());
return true;
}
diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp
index 73cfe8b..9e9f315 100644
--- a/test/Modules/normal-module-map.cpp
+++ b/test/Modules/normal-module-map.cpp
@@ -1,6 +1,5 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/normal-module-map %s -verify
-
#include "Umbrella/Umbrella.h"
int getUmbrella() {