bruno created this revision.

One of the -Wincomplete-umbrella warnings diagnoses when a header is present in 
the directory but it's not present in the umbrella header. Currently, this 
warning only happens on top level modules; any submodule using an umbrella 
header does not get this warning. Fix that by also considering the submodules.


https://reviews.llvm.org/D32576

Files:
  include/clang/Lex/Preprocessor.h
  lib/Lex/PPLexerChange.cpp
  test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h
  test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h
  test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap
  
test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap
  test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h
  test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h
  test/Modules/incomplete-umbrella.m

Index: test/Modules/incomplete-umbrella.m
===================================================================
--- /dev/null
+++ test/Modules/incomplete-umbrella.m
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F%S/Inputs/incomplete-umbrella -fsyntax-only %s 2>&1 | FileCheck %s
+
+#import <Foo/Foo.h>
+#import <Foo/Bar.h>
+#import <Foo/Baz.h>
+@import Foo.Private;
+
+// CHECK: warning: umbrella header for module 'Foo' does not include header 'Bar.h'
+// CHECK: warning: umbrella header for module 'Foo.Private' does not include header 'Baz.h'
+int foo() {
+  int a = BAR_PUBLIC;
+  int b = BAZ_PRIVATE;
+  return 0;
+}
Index: test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h
@@ -0,0 +1 @@
+// Foo.h
Index: test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h
@@ -0,0 +1 @@
+#define BAZ_PRIVATE 1
Index: test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap
===================================================================
--- /dev/null
+++ test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap
@@ -0,0 +1,5 @@
+explicit module Foo.Private {
+    umbrella header "Foo.h"
+    requires objc
+    export *
+}
Index: test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap
===================================================================
--- /dev/null
+++ test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module Foo {
+    umbrella header "FooPublic.h"
+    requires objc
+    export *
+}
Index: test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h
@@ -0,0 +1 @@
+// FooPublic.h
Index: test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h
@@ -0,0 +1 @@
+#define BAR_PUBLIC 1
Index: lib/Lex/PPLexerChange.cpp
===================================================================
--- lib/Lex/PPLexerChange.cpp
+++ lib/Lex/PPLexerChange.cpp
@@ -287,6 +287,49 @@
   return EndPos;
 }
 
+static void
+collectAllSubModulesWithUmbrellaHeader(Module *Mod,
+                                       SmallVectorImpl<Module *> &SubMods) {
+  if (Mod->getUmbrellaHeader())
+    SubMods.push_back(Mod);
+  for (auto *M : Mod->submodules())
+    collectAllSubModulesWithUmbrellaHeader(M, SubMods);
+}
+
+void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(Module *Mod) {
+  assert(Mod->getUmbrellaHeader() && "Module must use umbrella header");
+  SourceLocation StartLoc =
+      SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+  if (getDiagnostics().isIgnored(diag::warn_uncovered_module_header, StartLoc))
+    return;
+
+  ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+  const DirectoryEntry *Dir = Mod->getUmbrellaDir().Entry;
+  vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+  std::error_code EC;
+  for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End;
+       Entry != End && !EC; Entry.increment(EC)) {
+    using llvm::StringSwitch;
+
+    // Check whether this entry has an extension typically associated with
+    // headers.
+    if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
+             .Cases(".h", ".H", ".hh", ".hpp", true)
+             .Default(false))
+      continue;
+
+    if (const FileEntry *Header = getFileManager().getFile(Entry->getName()))
+      if (!getSourceManager().hasFileInfo(Header)) {
+        if (!ModMap.isHeaderInUnavailableModule(Header)) {
+          // Find the relative path that would access this header.
+          SmallString<128> RelativePath;
+          computeRelativePath(FileMgr, Dir, Header, RelativePath);
+          Diag(StartLoc, diag::warn_uncovered_module_header)
+              << Mod->getFullModuleName() << RelativePath;
+        }
+      }
+  }
+}
 
 /// HandleEndOfFile - This callback is invoked when the lexer hits the end of
 /// the current file.  This either returns the EOF token or pops a level off
@@ -473,44 +516,14 @@
   }
 
   // If we are building a module that has an umbrella header, make sure that
-  // each of the headers within the directory covered by the umbrella header
-  // was actually included by the umbrella header.
+  // each of the headers within the directory, including all submodules, is
+  // covered by the umbrella header was actually included by the umbrella
+  // header.
   if (Module *Mod = getCurrentModule()) {
-    if (Mod->getUmbrellaHeader()) {
-      SourceLocation StartLoc
-        = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
-
-      if (!getDiagnostics().isIgnored(diag::warn_uncovered_module_header,
-                                      StartLoc)) {
-        ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
-        const DirectoryEntry *Dir = Mod->getUmbrellaDir().Entry;
-        vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
-        std::error_code EC;
-        for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End;
-             Entry != End && !EC; Entry.increment(EC)) {
-          using llvm::StringSwitch;
-          
-          // Check whether this entry has an extension typically associated with
-          // headers.
-          if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
-                 .Cases(".h", ".H", ".hh", ".hpp", true)
-                 .Default(false))
-            continue;
-
-          if (const FileEntry *Header =
-                  getFileManager().getFile(Entry->getName()))
-            if (!getSourceManager().hasFileInfo(Header)) {
-              if (!ModMap.isHeaderInUnavailableModule(Header)) {
-                // Find the relative path that would access this header.
-                SmallString<128> RelativePath;
-                computeRelativePath(FileMgr, Dir, Header, RelativePath);              
-                Diag(StartLoc, diag::warn_uncovered_module_header)
-                  << Mod->getFullModuleName() << RelativePath;
-              }
-            }
-        }
-      }
-    }
+    llvm::SmallVector<Module *, 4> AllMods;
+    collectAllSubModulesWithUmbrellaHeader(Mod, AllMods);
+    for (auto *M : AllMods)
+      diagnoseMissingHeaderInUmbrellaDir(M);
   }
 
   return true;
Index: include/clang/Lex/Preprocessor.h
===================================================================
--- include/clang/Lex/Preprocessor.h
+++ include/clang/Lex/Preprocessor.h
@@ -1602,6 +1602,7 @@
                  *Ident_AbnormalTermination;
 
   const char *getCurLexerEndPos();
+  void diagnoseMissingHeaderInUmbrellaDir(Module *Mod);
 
 public:
   void PoisonSEHIdentifiers(bool Poison = true); // Borland
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D32576: [M... Bruno Cardoso Lopes via Phabricator via cfe-commits

Reply via email to