mirror of
https://github.com/intel/llvm.git
synced 2026-01-27 14:50:42 +08:00
Add -Wnon-modular-include* options
Warn on non-modular includes in various contexts. -Wnon-modular-include -Wnon-modular-include-in-module -Wnon-modular-include-in-framework-module Where each group is a subgroup of those above it. llvm-svn: 208004
This commit is contained in:
@@ -186,6 +186,12 @@ def IncompatiblePointerTypes
|
||||
[IncompatiblePointerTypesDiscardsQualifiers]>;
|
||||
def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">;
|
||||
def IncompleteModule : DiagGroup<"incomplete-module", [IncompleteUmbrella]>;
|
||||
def NonModularIncludeInFrameworkModule
|
||||
: DiagGroup<"non-modular-include-in-framework-module">;
|
||||
def NonModularIncludeInModule : DiagGroup<"non-modular-include-in-module",
|
||||
[NonModularIncludeInFrameworkModule]>;
|
||||
def NonModularInclude : DiagGroup<"non-modular-include",
|
||||
[NonModularIncludeInModule]>;
|
||||
def InvalidNoreturn : DiagGroup<"invalid-noreturn">;
|
||||
def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">;
|
||||
def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
|
||||
|
||||
@@ -620,6 +620,14 @@ def error_use_of_private_header_outside_module : Error<
|
||||
"use of private header from outside its module: '%0'">;
|
||||
def error_undeclared_use_of_module : Error<
|
||||
"module %0 does not depend on a module exporting '%1'">;
|
||||
def warn_non_modular_include_in_framework_module : Warning<
|
||||
"include of non-modular header inside framework module '%0'">,
|
||||
InGroup<NonModularIncludeInFrameworkModule>, DefaultIgnore;
|
||||
def warn_non_modular_include_in_module : Warning<
|
||||
"include of non-modular header inside module '%0'">,
|
||||
InGroup<NonModularIncludeInModule>, DefaultIgnore;
|
||||
def warn_non_modular_include : Warning<
|
||||
"include of non-modular header">, InGroup<NonModularInclude>, DefaultIgnore;
|
||||
|
||||
def warn_header_guard : Warning<
|
||||
"%0 is used as a header guard here, followed by #define of a different macro">,
|
||||
|
||||
@@ -195,6 +195,13 @@ private:
|
||||
KnownHeader findHeaderInUmbrellaDirs(const FileEntry *File,
|
||||
SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs);
|
||||
|
||||
/// \brief A convenience method to determine if \p File is (possibly nested)
|
||||
/// in an umbrella directory.
|
||||
bool isHeaderInUmbrellaDirs(const FileEntry *File) {
|
||||
SmallVector<const DirectoryEntry *, 2> IntermediateDirs;
|
||||
return static_cast<bool>(findHeaderInUmbrellaDirs(File, IntermediateDirs));
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Construct a new module map.
|
||||
///
|
||||
|
||||
@@ -230,56 +230,57 @@ static bool violatesPrivateInclude(Module *RequestingModule,
|
||||
RequestedModule->getTopLevelModule() != RequestingModule;
|
||||
}
|
||||
|
||||
static Module *getTopLevelOrNull(Module *M) {
|
||||
return M ? M->getTopLevelModule() : nullptr;
|
||||
}
|
||||
|
||||
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)
|
||||
if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule))
|
||||
return;
|
||||
|
||||
if (RequestingModule)
|
||||
resolveUses(RequestingModule, /*Complain=*/false);
|
||||
|
||||
HeadersMap::iterator Known = findKnownHeader(File);
|
||||
if (Known == Headers.end()) {
|
||||
if (LangOpts.ModulesStrictDeclUse)
|
||||
Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module)
|
||||
<< RequestingModule->getFullModuleName() << Filename;
|
||||
return;
|
||||
}
|
||||
|
||||
bool Excluded = false;
|
||||
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)
|
||||
HeadersMap::iterator Known = findKnownHeader(File);
|
||||
if (Known != Headers.end()) {
|
||||
for (const KnownHeader &Header : Known->second) {
|
||||
// Excluded headers don't really belong to a module.
|
||||
if (Header.getRole() == ModuleMap::ExcludedHeader) {
|
||||
Excluded = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If 'File' is part of 'RequestingModule' we can definitely include it.
|
||||
if (Header.getModule() == RequestingModule)
|
||||
return;
|
||||
|
||||
// Remember private headers for later printing of a diagnostic.
|
||||
if (violatesPrivateInclude(RequestingModule, File, Header.getRole(),
|
||||
Header.getModule())) {
|
||||
Private = Header.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, Header.getModule())) {
|
||||
NotUsed = Header.getModule();
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have found a module that we can happily use.
|
||||
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.
|
||||
@@ -296,7 +297,22 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
|
||||
return;
|
||||
}
|
||||
|
||||
// Headers for which we have not found a module are fine to include.
|
||||
if (Excluded || isHeaderInUmbrellaDirs(File))
|
||||
return;
|
||||
|
||||
// At this point, only non-modular includes remain.
|
||||
|
||||
if (LangOpts.ModulesStrictDeclUse) {
|
||||
Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module)
|
||||
<< RequestingModule->getFullModuleName() << Filename;
|
||||
} else if (RequestingModule) {
|
||||
diag::kind DiagID = RequestingModule->getTopLevelModule()->IsFramework ?
|
||||
diag::warn_non_modular_include_in_framework_module :
|
||||
diag::warn_non_modular_include_in_module;
|
||||
Diags.Report(FilenameLoc, DiagID) << RequestingModule->getFullModuleName();
|
||||
} else {
|
||||
Diags.Report(FilenameLoc, diag::warn_non_modular_include);
|
||||
}
|
||||
}
|
||||
|
||||
ModuleMap::KnownHeader
|
||||
|
||||
@@ -611,22 +611,32 @@ const FileEntry *Preprocessor::LookupFile(
|
||||
// to one of the headers on the #include stack. Walk the list of the current
|
||||
// headers on the #include stack and pass them to HeaderInfo.
|
||||
if (IsFileLexer()) {
|
||||
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
|
||||
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) {
|
||||
if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
|
||||
SearchPath, RelativePath,
|
||||
SuggestedModule)))
|
||||
SuggestedModule))) {
|
||||
if (SuggestedModule && !LangOpts.AsmPreprocessor)
|
||||
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
|
||||
getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
|
||||
return FE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
|
||||
IncludeStackInfo &ISEntry = IncludeMacroStack[e-i-1];
|
||||
if (IsFileLexer(ISEntry)) {
|
||||
if ((CurFileEnt =
|
||||
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
|
||||
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID()))) {
|
||||
if ((FE = HeaderInfo.LookupSubframeworkHeader(
|
||||
Filename, CurFileEnt, SearchPath, RelativePath,
|
||||
SuggestedModule)))
|
||||
SuggestedModule))) {
|
||||
if (SuggestedModule && !LangOpts.AsmPreprocessor)
|
||||
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
|
||||
getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
|
||||
return FE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "B/B.h"
|
||||
@@ -0,0 +1 @@
|
||||
// AnotherModule.h
|
||||
@@ -0,0 +1 @@
|
||||
// AnotherModuleExcluded.h
|
||||
@@ -0,0 +1 @@
|
||||
#include "C.h"
|
||||
1
clang/test/Modules/Inputs/require-modular-includes/C.h
Normal file
1
clang/test/Modules/Inputs/require-modular-includes/C.h
Normal file
@@ -0,0 +1 @@
|
||||
// C.h
|
||||
@@ -0,0 +1 @@
|
||||
#include "AnotherModuleExcluded.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "AnotherModule.h"
|
||||
@@ -0,0 +1,2 @@
|
||||
// FromImportedModuleFail.h
|
||||
#include "NotInModule.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "FromImportedModuleOK2.h"
|
||||
@@ -0,0 +1 @@
|
||||
// FromImportedModuleOK2.h
|
||||
@@ -0,0 +1,4 @@
|
||||
framework module FromImportedModuleOK {
|
||||
header "FromImportedModuleOK.h"
|
||||
header "FromImportedModuleOK2.h"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Header.h
|
||||
#include "NotInModule.h"
|
||||
@@ -0,0 +1,5 @@
|
||||
framework module FromImportedSubModule {
|
||||
module Sub {
|
||||
header "Header.h"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "Subframework/Subframework.h"
|
||||
@@ -0,0 +1,3 @@
|
||||
framework module FromNonModularSubframework {
|
||||
header "FromNonModularSubframework.h"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
// Subframework.h
|
||||
@@ -0,0 +1 @@
|
||||
#include "Subframework/Subframework.h"
|
||||
@@ -0,0 +1,7 @@
|
||||
framework module FromSubframework {
|
||||
umbrella header "FromSubframework.h"
|
||||
|
||||
framework module Subframework {
|
||||
umbrella header "Subframework.h"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "umbrella/foo.h"
|
||||
#include "umbrella/bar/bar.h"
|
||||
@@ -0,0 +1 @@
|
||||
// Excluded.h
|
||||
@@ -0,0 +1 @@
|
||||
#include "Excluded.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
framework module IncludeExcluded {
|
||||
header "IncludeExcluded.h"
|
||||
exclude header "Excluded.h"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// NotFramework.h
|
||||
#import "NotInModule.h"
|
||||
@@ -0,0 +1 @@
|
||||
// NotInModule.h
|
||||
@@ -0,0 +1,12 @@
|
||||
module AnotherModule {
|
||||
header "AnotherModule.h"
|
||||
exclude header "AnotherModuleExcluded.h"
|
||||
}
|
||||
module Umbrella {
|
||||
umbrella "umbrella"
|
||||
}
|
||||
module NotFramework {
|
||||
header "NotFramework.h"
|
||||
}
|
||||
|
||||
framework module * { }
|
||||
@@ -0,0 +1 @@
|
||||
// bar.h
|
||||
@@ -0,0 +1 @@
|
||||
// foo.h
|
||||
95
clang/test/Modules/require-modular-includes.m
Normal file
95
clang/test/Modules/require-modular-includes.m
Normal file
@@ -0,0 +1,95 @@
|
||||
// RUN: rm -rf %t
|
||||
// REQUIRES: shell
|
||||
|
||||
// Including a header from the imported module
|
||||
// RUN: echo '@import FromImportedModuleOK;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fsyntax-only -x objective-c -
|
||||
|
||||
// Including a non-modular header
|
||||
// RUN: echo '@import FromImportedModuleFail;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -fsyntax-only -x objective-c - 2>&1 | FileCheck %s
|
||||
|
||||
// Including a header from a subframework
|
||||
// RUN: echo '@import FromSubframework;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fsyntax-only -x objective-c -
|
||||
|
||||
// Including a header from a subframework (fail)
|
||||
// RUN: echo '@import FromNonModularSubframework;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -fsyntax-only -x objective-c - 2>&1 | FileCheck %s
|
||||
|
||||
// Including a non-modular header from a submodule
|
||||
// RUN: echo '@import FromImportedSubModule;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -fsyntax-only -x objective-c - 2>&1 | FileCheck %s
|
||||
|
||||
// Including a non-modular header (directly) with -fmodule-name set
|
||||
// RUN: echo '#include "NotInModule.h"' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fmodule-name=A -fsyntax-only -x objective-c -
|
||||
|
||||
// Including a non-modular header (directly) with -Wnon-modular-include
|
||||
// RUN: echo '#include "NotInModule.h"' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -fmodule-name=A -fsyntax-only -x objective-c - 2>&1 | FileCheck %s
|
||||
|
||||
// Including an excluded header
|
||||
// RUN: echo '@import IncludeExcluded;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fsyntax-only -x objective-c -
|
||||
|
||||
// Including a header from another module
|
||||
// RUN: echo '@import FromAnotherModule;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fsyntax-only -x objective-c -
|
||||
|
||||
// Including an excluded header from another module
|
||||
// RUN: echo '@import ExcludedFromAnotherModule;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fsyntax-only -x objective-c -
|
||||
|
||||
// Including a header from an umbrella directory
|
||||
// RUN: echo '@import FromUmbrella;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fsyntax-only -x objective-c -
|
||||
|
||||
// A includes B includes non-modular C
|
||||
// RUN: echo '@import A;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -F %S/Inputs/require-modular-includes \
|
||||
// RUN: -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -fsyntax-only -x objective-c - 2>&1 | FileCheck %s
|
||||
|
||||
// Non-framework module (pass)
|
||||
// RUN: echo '@import NotFramework;' | \
|
||||
// RUN: %clang_cc1 -Wnon-modular-include-in-framework-module -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -Werror -fsyntax-only -x objective-c -
|
||||
|
||||
// Non-framework module (fail)
|
||||
// RUN: echo '@import NotFramework;' | \
|
||||
// RUN: not %clang_cc1 -Werror=non-modular-include -fmodules \
|
||||
// RUN: -fmodules-cache-path=%t -I %S/Inputs/require-modular-includes \
|
||||
// RUN: -fsyntax-only -x objective-c - 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: include of non-modular header
|
||||
Reference in New Issue
Block a user