From 261e75bd10198c336aded42f0398a13f7bf88889 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 16 Nov 2011 17:04:00 +0000 Subject: [PATCH] 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 --- .../clang/Basic/DiagnosticFrontendKinds.td | 2 + lib/Frontend/FrontendActions.cpp | 104 ++++++++++++++++-- test/Modules/normal-module-map.cpp | 1 - 3 files changed, 97 insertions(+), 10 deletions(-) diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 167d070f54..f48e9e3809 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -178,4 +178,6 @@ def err_missing_module_name : Error< 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 243f5277ab..8e2e21564f 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -126,6 +126,38 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, 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::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 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, 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 73cfe8b675..9e9f31578d 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() { -- 2.40.0