]> granicus.if.org Git - clang/commitdiff
When building a module with an umbrella header, warn about any headers
authorDouglas Gregor <dgregor@apple.com>
Fri, 23 Dec 2011 00:23:59 +0000 (00:23 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 23 Dec 2011 00:23:59 +0000 (00:23 +0000)
found within that umbrella directory that were not actually included
by the umbrella header. They should either be referenced in the module
map or included by the umbrella header.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147207 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticLexKinds.td
lib/Lex/PPLexerChange.cpp
test/Modules/Inputs/Module.framework/Headers/Module.h
test/Modules/on-demand-build.m

index cc202b48e53d20a6be73442fc632f9fba70a419e..62bd3158423ac0f605caee968df572934c9d70b3 100644 (file)
@@ -425,5 +425,7 @@ def err_mmap_nested_submodule_id : Error<
 def warn_auto_module_import : Warning<
   "treating #%select{include|import|include_next|__include_macros}0 as an "
   "import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;
+def warn_uncovered_module_header : Warning<
+  "umbrella header does not include header '%0'">, InGroup<IncompleteUmbrella>;
 
 }
index 24dda4f84c893eede720cd3f5c4dafcca57d74de..b8839851ec03d297b12d209a22ff92eeb9c3c832 100644 (file)
 #include "clang/Lex/LexDiagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
+#include "llvm/ADT/StringSwitch.h"
 using namespace clang;
 
 PPCallbacks::~PPCallbacks() {}
@@ -199,6 +202,31 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
     CurLexerKind = CLK_TokenLexer;
 }
 
+/// \brief Compute the relative path that names the given file relative to
+/// the given directory.
+static void computeRelativePath(FileManager &FM, const DirectoryEntry *Dir,
+                                const FileEntry *File,
+                                llvm::SmallString<128> &Result) {
+  Result.clear();
+
+  StringRef FilePath = File->getDir()->getName();
+  StringRef Path = FilePath;
+  while (!Path.empty()) {
+    if (const DirectoryEntry *CurDir = FM.getDirectory(Path)) {
+      if (CurDir == Dir) {
+        Result = FilePath.substr(Path.size());
+        llvm::sys::path::append(Result, 
+                                llvm::sys::path::filename(File->getName()));
+        return;
+      }
+    }
+    
+    Path = llvm::sys::path::parent_path(Path);
+  }
+  
+  Result = File->getName();
+}
+
 /// 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
 /// the include stack and keeps going.
@@ -316,6 +344,45 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
          I=WarnUnusedMacroLocs.begin(), E=WarnUnusedMacroLocs.end(); I!=E; ++I)
     Diag(*I, diag::pp_macro_not_used);
 
+  // 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.
+  if (Module *Mod = getCurrentModule()) {
+    if (Mod->getUmbrellaHeader()) {
+      SourceLocation StartLoc
+        = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+
+      if (getDiagnostics().getDiagnosticLevel(
+            diag::warn_uncovered_module_header, 
+            StartLoc) != DiagnosticsEngine::Ignored) {
+        typedef typename llvm::sys::fs::recursive_directory_iterator
+          recursive_directory_iterator;
+        const DirectoryEntry *Dir = Mod->getUmbrellaDir();
+        llvm::error_code EC;
+        for (recursive_directory_iterator Entry(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->path()))
+              .Cases(".h", ".H", ".hh", ".hpp", true)
+              .Default(false))
+            continue;
+
+          if (const FileEntry *Header = getFileManager().getFile(Entry->path()))
+            if (!getSourceManager().hasFileInfo(Header)) {
+              // Find the 
+              llvm::SmallString<128> RelativePath;
+              computeRelativePath(FileMgr, Dir, Header, RelativePath);              
+              Diag(StartLoc, diag::warn_uncovered_module_header)
+                << RelativePath;
+            }
+        }
+      }
+    }
+  }
+  
   return true;
 }
 
index be88bb5adc260290acf146c8d019252c6226dad5..3d10112e55475511d39bf12972e762e40f6735c0 100644 (file)
@@ -1,3 +1,5 @@
+// expected-warning{{umbrella header}}
+
 #ifndef MODULE_H
 #define MODULE_H
 const char *getModuleVersion(void);
index 7843014453b6b92bc71b73cf913517ca22879e0f..644519b9728bd495b01f129f2603ff6b7a51685f 100644 (file)
@@ -1,13 +1,15 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -fmodule-cache-path %t -F %S/Inputs -verify %s
-// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -x objective-c++ -fmodule-cache-path %t -F %S/Inputs -verify %s
-// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -x objective-c++ -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodule-cache-path %t -F %S/Inputs -verify %s
 #define FOO
 __import_module__ Module;
 @interface OtherClass
 @end
 
 
+
+
 // in module: expected-note{{class method 'alloc' is assumed to return an instance of its receiver type ('Module *')}}
 void test_getModuleVersion() {
   const char *version = getModuleVersion();