aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
authorDaniel Jasper <djasper@google.com>2013-12-20 12:09:36 +0000
committerDaniel Jasper <djasper@google.com>2013-12-20 12:09:36 +0000
commit92669ee45cc4337d2871eac16eb07b2fe8372373 (patch)
tree9da877273945971737c154ca094694232747ad01 /clang/lib/Lex/ModuleMap.cpp
parent83a0b6abd0f43ee3ed6755fa9c8a2e3ee13e04e7 (diff)
downloadllvm-92669ee45cc4337d2871eac16eb07b2fe8372373.zip
llvm-92669ee45cc4337d2871eac16eb07b2fe8372373.tar.gz
llvm-92669ee45cc4337d2871eac16eb07b2fe8372373.tar.bz2
Enable layering check in unavailable modules.
If a header file belonging to a certain module is not found on the filesystem, that header gets marked as unavailable. Now, the layering warning (-fmodules-decluse) should still warn about headers of this module being wrongfully included. Currently, headers belonging to those modules are just treated as not belonging to modules at all which means they can be included freely from everywhere. To implement this (somewhat) cleanly, I have moved most of the layering checks into the ModuleMap. This will also help with showing FixIts later. llvm-svn: 197805
Diffstat (limited to 'clang/lib/Lex/ModuleMap.cpp')
-rw-r--r--clang/lib/Lex/ModuleMap.cpp119
1 files changed, 104 insertions, 15 deletions
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index b9a4703..0523827 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -159,21 +159,115 @@ static bool isBuiltinHeader(StringRef FileName) {
.Default(false);
}
-ModuleMap::KnownHeader
-ModuleMap::findModuleForHeader(const FileEntry *File,
- Module *RequestingModule,
- bool *FoundInModule) {
+ModuleMap::HeadersMap::iterator
+ModuleMap::findKnownHeader(const FileEntry *File) {
HeadersMap::iterator Known = Headers.find(File);
-
- // If we've found a builtin header within Clang's builtin include directory,
- // load all of the module maps to see if it will get associated with a
- // specific module (e.g., in /usr/include).
if (Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
HeaderInfo.loadTopLevelSystemModules();
- Known = Headers.find(File);
+ return Headers.find(File);
+ }
+ return Known;
+}
+
+// Returns 'true' if 'RequestingModule directly uses 'RequestedModule'.
+static bool directlyUses(const Module *RequestingModule,
+ const Module *RequestedModule) {
+ return std::find(RequestingModule->DirectUses.begin(),
+ RequestingModule->DirectUses.end(),
+ RequestedModule) != RequestingModule->DirectUses.end();
+}
+
+static bool violatesPrivateInclude(Module *RequestingModule,
+ const FileEntry *IncFileEnt,
+ ModuleMap::ModuleHeaderRole Role,
+ Module *RequestedModule) {
+ #ifndef NDEBUG
+ // Check for consistency between the module header role
+ // as obtained from the lookup and as obtained from the module.
+ // This check is not cheap, so enable it only for debugging.
+ SmallVectorImpl<const FileEntry *> &PvtHdrs
+ = RequestedModule->PrivateHeaders;
+ SmallVectorImpl<const FileEntry *>::iterator Look
+ = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt);
+ bool IsPrivate = Look != PvtHdrs.end();
+ assert((IsPrivate && Role == ModuleMap::PrivateHeader)
+ || (!IsPrivate && Role != ModuleMap::PrivateHeader));
+ #endif
+ return Role == ModuleMap::PrivateHeader &&
+ RequestedModule->getTopLevelModule() != RequestingModule;
+}
+
+void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
+ SourceLocation FilenameLoc,
+ StringRef Filename,
+ const FileEntry *File) {
+ // No errors for indirect modules. This may be a bit of a problem for modules
+ // with no source files.
+ if (RequestingModule != SourceModule)
+ return;
+
+ if (RequestingModule)
+ resolveUses(RequestingModule, /*Complain=*/false);
+
+ HeadersMap::iterator Known = findKnownHeader(File);
+ if (Known == Headers.end())
+ return;
+
+ Module *Private = NULL;
+ Module *NotUsed = NULL;
+ for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ // Excluded headers don't really belong to a module.
+ if (I->getRole() == ModuleMap::ExcludedHeader)
+ continue;
+
+ // If 'File' is part of 'RequestingModule' we can definitely include it.
+ if (I->getModule() == RequestingModule)
+ return;
+
+ // Remember private headers for later printing of a diagnostic.
+ if (violatesPrivateInclude(RequestingModule, File, I->getRole(),
+ I->getModule())) {
+ Private = I->getModule();
+ continue;
+ }
+
+ // If uses need to be specified explicitly, we are only allowed to return
+ // modules that are explicitly used by the requesting module.
+ if (RequestingModule && LangOpts.ModulesDeclUse &&
+ !directlyUses(RequestingModule, I->getModule())) {
+ NotUsed = I->getModule();
+ continue;
+ }
+
+ // We have found a module that we can happily use.
+ return;
+ }
+
+ // We have found a header, but it is private.
+ if (Private != NULL) {
+ Diags.Report(FilenameLoc, diag::error_use_of_private_header_outside_module)
+ << Filename;
+ return;
}
+ // We have found a module, but we don't use it.
+ if (NotUsed != NULL) {
+ Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module)
+ << RequestingModule->getFullModuleName() << Filename;
+ return;
+ }
+
+ // Headers for which we have not found a module are fine to include.
+}
+
+ModuleMap::KnownHeader
+ModuleMap::findModuleForHeader(const FileEntry *File,
+ Module *RequestingModule) {
+ HeadersMap::iterator Known = findKnownHeader(File);
+
if (Known != Headers.end()) {
ModuleMap::KnownHeader Result = KnownHeader();
@@ -185,9 +279,6 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
if (I->getRole() == ModuleMap::ExcludedHeader)
continue;
- if (FoundInModule)
- *FoundInModule = true;
-
// Cannot use a module if it is unavailable.
if (!I->getModule()->isAvailable())
continue;
@@ -200,9 +291,7 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
// If uses need to be specified explicitly, we are only allowed to return
// modules that are explicitly used by the requesting module.
if (RequestingModule && LangOpts.ModulesDeclUse &&
- std::find(RequestingModule->DirectUses.begin(),
- RequestingModule->DirectUses.end(),
- I->getModule()) == RequestingModule->DirectUses.end())
+ !directlyUses(RequestingModule, I->getModule()))
continue;
Result = *I;