mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #60659 from xymus/print-missing-imports
[ModuleInterface] Print missing imports in swiftinterface
This commit is contained in:
@@ -5855,6 +5855,10 @@ ERROR(inlinable_typealias_desugars_to_type_from_hidden_module,
|
|||||||
"%4 was not imported by this file}5",
|
"%4 was not imported by this file}5",
|
||||||
(DeclName, StringRef, StringRef, unsigned, Identifier, unsigned))
|
(DeclName, StringRef, StringRef, unsigned, Identifier, unsigned))
|
||||||
|
|
||||||
|
NOTE(missing_import_inserted,
|
||||||
|
none, "The missing import of module %0 will be added implicitly",
|
||||||
|
(Identifier))
|
||||||
|
|
||||||
ERROR(availability_macro_in_inlinable, none,
|
ERROR(availability_macro_in_inlinable, none,
|
||||||
"availability macro cannot be used in " FRAGILE_FUNC_KIND "0",
|
"availability macro cannot be used in " FRAGILE_FUNC_KIND "0",
|
||||||
(unsigned))
|
(unsigned))
|
||||||
|
|||||||
@@ -271,6 +271,10 @@ public:
|
|||||||
getImportedModules(SmallVectorImpl<ImportedModule> &imports,
|
getImportedModules(SmallVectorImpl<ImportedModule> &imports,
|
||||||
ModuleDecl::ImportFilter filter) const {}
|
ModuleDecl::ImportFilter filter) const {}
|
||||||
|
|
||||||
|
/// Lists modules that are not imported from this file and used in API.
|
||||||
|
virtual void
|
||||||
|
getMissingImportedModules(SmallVectorImpl<ImportedModule> &imports) const {}
|
||||||
|
|
||||||
/// \see ModuleDecl::getImportedModulesForLookup
|
/// \see ModuleDecl::getImportedModulesForLookup
|
||||||
virtual void getImportedModulesForLookup(
|
virtual void getImportedModulesForLookup(
|
||||||
SmallVectorImpl<ImportedModule> &imports) const {
|
SmallVectorImpl<ImportedModule> &imports) const {
|
||||||
|
|||||||
@@ -712,6 +712,10 @@ public:
|
|||||||
void getImportedModules(SmallVectorImpl<ImportedModule> &imports,
|
void getImportedModules(SmallVectorImpl<ImportedModule> &imports,
|
||||||
ImportFilter filter = ImportFilterKind::Exported) const;
|
ImportFilter filter = ImportFilterKind::Exported) const;
|
||||||
|
|
||||||
|
/// Lists modules that are not imported from a file and used in API.
|
||||||
|
void
|
||||||
|
getMissingImportedModules(SmallVectorImpl<ImportedModule> &imports) const;
|
||||||
|
|
||||||
/// Looks up which modules are imported by this module, ignoring any that
|
/// Looks up which modules are imported by this module, ignoring any that
|
||||||
/// won't contain top-level decls.
|
/// won't contain top-level decls.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -399,6 +399,15 @@ public:
|
|||||||
|
|
||||||
SWIFT_DEBUG_DUMPER(dumpSeparatelyImportedOverlays());
|
SWIFT_DEBUG_DUMPER(dumpSeparatelyImportedOverlays());
|
||||||
|
|
||||||
|
llvm::SmallDenseSet<ImportedModule> MissingImportedModules;
|
||||||
|
|
||||||
|
void addMissingImportedModule(ImportedModule module) const {
|
||||||
|
const_cast<SourceFile *>(this)->MissingImportedModules.insert(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getMissingImportedModules(
|
||||||
|
SmallVectorImpl<ImportedModule> &imports) const override;
|
||||||
|
|
||||||
void cacheVisibleDecls(SmallVectorImpl<ValueDecl *> &&globals) const;
|
void cacheVisibleDecls(SmallVectorImpl<ValueDecl *> &&globals) const;
|
||||||
const SmallVectorImpl<ValueDecl *> &getCachedVisibleDecls() const;
|
const SmallVectorImpl<ValueDecl *> &getCachedVisibleDecls() const;
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ struct ModuleInterfaceOptions {
|
|||||||
/// when PrintSPIs is true.
|
/// when PrintSPIs is true.
|
||||||
bool ExperimentalSPIImports = false;
|
bool ExperimentalSPIImports = false;
|
||||||
|
|
||||||
|
/// Print imports that are missing from the source and used in API.
|
||||||
|
bool PrintMissingImports = true;
|
||||||
|
|
||||||
/// Intentionally print invalid syntax into the file.
|
/// Intentionally print invalid syntax into the file.
|
||||||
bool DebugPrintInvalidSyntax = false;
|
bool DebugPrintInvalidSyntax = false;
|
||||||
|
|
||||||
|
|||||||
@@ -900,6 +900,11 @@ def experimental_spi_imports :
|
|||||||
Flag<["-"], "experimental-spi-imports">,
|
Flag<["-"], "experimental-spi-imports">,
|
||||||
HelpText<"Enable experimental support for SPI imports">;
|
HelpText<"Enable experimental support for SPI imports">;
|
||||||
|
|
||||||
|
def disable_print_missing_imports_in_module_interface :
|
||||||
|
Flag<["-"], "disable-print-missing-imports-in-module-interface">,
|
||||||
|
HelpText<"Disable adding to the module interface imports used from API and "
|
||||||
|
"missing from the sources">;
|
||||||
|
|
||||||
// [FIXME: Clang-type-plumbing] Make this a SIL-only option once we start
|
// [FIXME: Clang-type-plumbing] Make this a SIL-only option once we start
|
||||||
// unconditionally emitting non-canonical Clang types in swiftinterfaces.
|
// unconditionally emitting non-canonical Clang types in swiftinterfaces.
|
||||||
def experimental_print_full_convention :
|
def experimental_print_full_convention :
|
||||||
|
|||||||
@@ -1570,6 +1570,11 @@ void ModuleDecl::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
|
|||||||
FORWARD(getImportedModules, (modules, filter));
|
FORWARD(getImportedModules, (modules, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModuleDecl::getMissingImportedModules(
|
||||||
|
SmallVectorImpl<ImportedModule> &imports) const {
|
||||||
|
FORWARD(getMissingImportedModules, (imports));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceFile::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
|
SourceFile::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
|
||||||
ModuleDecl::ImportFilter filter) const {
|
ModuleDecl::ImportFilter filter) const {
|
||||||
@@ -1604,6 +1609,12 @@ SourceFile::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SourceFile::getMissingImportedModules(
|
||||||
|
SmallVectorImpl<ImportedModule> &modules) const {
|
||||||
|
for (auto module : MissingImportedModules)
|
||||||
|
modules.push_back(module);
|
||||||
|
}
|
||||||
|
|
||||||
void SourceFile::dumpSeparatelyImportedOverlays() const {
|
void SourceFile::dumpSeparatelyImportedOverlays() const {
|
||||||
for (auto &pair : separatelyImportedOverlays) {
|
for (auto &pair : separatelyImportedOverlays) {
|
||||||
auto &underlying = std::get<0>(pair);
|
auto &underlying = std::get<0>(pair);
|
||||||
@@ -2535,6 +2546,21 @@ RestrictedImportKind SourceFile::getRestrictedImportKind(const ModuleDecl *modul
|
|||||||
if (imports.isImportedBy(module, getParentModule()))
|
if (imports.isImportedBy(module, getParentModule()))
|
||||||
return RestrictedImportKind::None;
|
return RestrictedImportKind::None;
|
||||||
|
|
||||||
|
if (importKind == RestrictedImportKind::Implicit &&
|
||||||
|
(module->getLibraryLevel() == LibraryLevel::API ||
|
||||||
|
getParentModule()->getLibraryLevel() != LibraryLevel::API)) {
|
||||||
|
// Hack to fix swiftinterfaces in case of missing imports.
|
||||||
|
// We can get rid of this logic when we don't leak the use of non-locally
|
||||||
|
// imported things in API.
|
||||||
|
ImportPath::Element pathElement = {module->getName(), SourceLoc()};
|
||||||
|
auto pathArray = getASTContext().AllocateCopy(
|
||||||
|
llvm::makeArrayRef(pathElement));
|
||||||
|
auto missingImport = ImportedModule(
|
||||||
|
ImportPath::Access(pathArray),
|
||||||
|
const_cast<ModuleDecl *>(module));
|
||||||
|
addMissingImportedModule(missingImport);
|
||||||
|
}
|
||||||
|
|
||||||
return importKind;
|
return importKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -373,6 +373,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
|
|||||||
Args.hasArg(OPT_experimental_spi_imports);
|
Args.hasArg(OPT_experimental_spi_imports);
|
||||||
Opts.DebugPrintInvalidSyntax |=
|
Opts.DebugPrintInvalidSyntax |=
|
||||||
Args.hasArg(OPT_debug_emit_invalid_swiftinterface_syntax);
|
Args.hasArg(OPT_debug_emit_invalid_swiftinterface_syntax);
|
||||||
|
Opts.PrintMissingImports =
|
||||||
|
!Args.hasArg(OPT_disable_print_missing_imports_in_module_interface);
|
||||||
|
|
||||||
if (const Arg *A = Args.getLastArg(OPT_library_level)) {
|
if (const Arg *A = Args.getLastArg(OPT_library_level)) {
|
||||||
StringRef contents = A->getValue();
|
StringRef contents = A->getValue();
|
||||||
|
|||||||
@@ -219,6 +219,10 @@ static void printImports(raw_ostream &out,
|
|||||||
|
|
||||||
SmallVector<ImportedModule, 8> allImports;
|
SmallVector<ImportedModule, 8> allImports;
|
||||||
M->getImportedModules(allImports, allImportFilter);
|
M->getImportedModules(allImports, allImportFilter);
|
||||||
|
|
||||||
|
if (Opts.PrintMissingImports)
|
||||||
|
M->getMissingImportedModules(allImports);
|
||||||
|
|
||||||
ImportedModule::removeDuplicates(allImports);
|
ImportedModule::removeDuplicates(allImports);
|
||||||
diagnoseScopedImports(M->getASTContext().Diags, allImports);
|
diagnoseScopedImports(M->getASTContext().Diags, allImports);
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,11 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc,
|
|||||||
}
|
}
|
||||||
D->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
|
D->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
|
||||||
|
|
||||||
|
if (originKind == DisallowedOriginKind::ImplicitlyImported &&
|
||||||
|
!ctx.LangOpts.isSwiftVersionAtLeast(6))
|
||||||
|
ctx.Diags.diagnose(loc, diag::missing_import_inserted,
|
||||||
|
definingModule->getName());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +195,13 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
|
|||||||
D->getDescriptiveKind(), D->getName(),
|
D->getDescriptiveKind(), D->getName(),
|
||||||
fragileKind.getSelector(), definingModule->getName(),
|
fragileKind.getSelector(), definingModule->getName(),
|
||||||
static_cast<unsigned>(originKind));
|
static_cast<unsigned>(originKind));
|
||||||
|
|
||||||
|
if (originKind == DisallowedOriginKind::ImplicitlyImported &&
|
||||||
|
downgradeToWarning == DowngradeToWarning::Yes)
|
||||||
|
ctx.Diags.diagnose(loc, diag::missing_import_inserted,
|
||||||
|
definingModule->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,5 +256,10 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc,
|
|||||||
!ctx.LangOpts.EnableConformanceAvailabilityErrors) ||
|
!ctx.LangOpts.EnableConformanceAvailabilityErrors) ||
|
||||||
originKind == DisallowedOriginKind::ImplicitlyImported,
|
originKind == DisallowedOriginKind::ImplicitlyImported,
|
||||||
6);
|
6);
|
||||||
|
|
||||||
|
if (originKind == DisallowedOriginKind::ImplicitlyImported &&
|
||||||
|
!ctx.LangOpts.isSwiftVersionAtLeast(6))
|
||||||
|
ctx.Diags.diagnose(loc, diag::missing_import_inserted,
|
||||||
|
M->getName());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,14 @@
|
|||||||
/// In Swift 6, it's an error.
|
/// In Swift 6, it's an error.
|
||||||
// RUN: %target-swift-frontend -emit-module %t/clientFileA-Swift6.swift %t/clientFileB.swift -module-name client -o %t/client.swiftmodule -I %t -verify -swift-version 6
|
// RUN: %target-swift-frontend -emit-module %t/clientFileA-Swift6.swift %t/clientFileB.swift -module-name client -o %t/client.swiftmodule -I %t -verify -swift-version 6
|
||||||
|
|
||||||
|
/// The swiftinterface is broken by the missing import without the workaround.
|
||||||
|
// RUN: %target-swift-emit-module-interface(%t/ClientBroken.swiftinterface) %t/clientFileA-Swift5.swift %t/clientFileB.swift -I %t -disable-print-missing-imports-in-module-interface
|
||||||
|
// RUN: not %target-swift-typecheck-module-from-interface(%t/ClientBroken.swiftinterface) -I %t
|
||||||
|
|
||||||
|
/// The swiftinterface parses fine with the workaround adding the missing imports.
|
||||||
|
// RUN: %target-swift-emit-module-interface(%t/ClientFixed.swiftinterface) %t/clientFileA-Swift5.swift %t/clientFileB.swift -I %t
|
||||||
|
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientFixed.swiftinterface) -I %t
|
||||||
|
|
||||||
// REQUIRES: asserts
|
// REQUIRES: asserts
|
||||||
|
|
||||||
// BEGIN empty.swift
|
// BEGIN empty.swift
|
||||||
@@ -45,11 +53,13 @@ import libA
|
|||||||
@inlinable public func bar() {
|
@inlinable public func bar() {
|
||||||
let a = ImportedType()
|
let a = ImportedType()
|
||||||
a.implicitlyImportedMethod() // expected-warning {{instance method 'implicitlyImportedMethod()' cannot be used in an '@inlinable' function because 'libB' was not imported by this file; this is an error in Swift 6}}
|
a.implicitlyImportedMethod() // expected-warning {{instance method 'implicitlyImportedMethod()' cannot be used in an '@inlinable' function because 'libB' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@-1 {{The missing import of module 'libB' will be added implicitly}}
|
||||||
|
|
||||||
// Expected implicit imports are still fine
|
// Expected implicit imports are still fine
|
||||||
a.localModuleMethod()
|
a.localModuleMethod()
|
||||||
|
|
||||||
conformanceUse(a) // expected-warning {{cannot use conformance of 'ImportedType' to 'SomeProtocol' here; 'libB' was not imported by this file; this is an error in Swift 6}}
|
conformanceUse(a) // expected-warning {{cannot use conformance of 'ImportedType' to 'SomeProtocol' here; 'libB' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@-1 {{The missing import of module 'libB' will be added implicitly}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BEGIN clientFileA-OldCheck.swift
|
// BEGIN clientFileA-OldCheck.swift
|
||||||
@@ -64,6 +74,7 @@ import libA
|
|||||||
a.localModuleMethod()
|
a.localModuleMethod()
|
||||||
|
|
||||||
conformanceUse(a) // expected-warning {{cannot use conformance of 'ImportedType' to 'SomeProtocol' here; 'libB' was not imported by this file; this is an error in Swift 6}}
|
conformanceUse(a) // expected-warning {{cannot use conformance of 'ImportedType' to 'SomeProtocol' here; 'libB' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@-1 {{The missing import of module 'libB' will be added implicitly}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BEGIN clientFileA-Swift6.swift
|
// BEGIN clientFileA-Swift6.swift
|
||||||
|
|||||||
@@ -11,6 +11,19 @@
|
|||||||
// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesImplementationOnlyImport.swift -I %t
|
// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesImplementationOnlyImport.swift -I %t
|
||||||
// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesWithImport.swift -I %t
|
// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesWithImport.swift -I %t
|
||||||
|
|
||||||
|
/// The swiftinterface is broken by the missing import without the workaround.
|
||||||
|
// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImport.swiftinterface) %t/UsesAliasesNoImport.swift -I %t \
|
||||||
|
// RUN: -disable-print-missing-imports-in-module-interface
|
||||||
|
// RUN: not %target-swift-typecheck-module-from-interface(%t/UsesAliasesNoImport.swiftinterface) -I %t
|
||||||
|
|
||||||
|
/// The swiftinterface parses fine with the workaround adding the missing imports.
|
||||||
|
// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImportFixed.swiftinterface) %t/UsesAliasesNoImport.swift -I %t
|
||||||
|
// RUN: %target-swift-typecheck-module-from-interface(%t/UsesAliasesNoImportFixed.swiftinterface) -I %t
|
||||||
|
|
||||||
|
/// The module with an implementation-only import is not affected by the workaround and remains broken.
|
||||||
|
// RUN: %target-swift-emit-module-interface(%t/UsesAliasesImplementationOnlyImport.swiftinterface) %t/UsesAliasesImplementationOnlyImport.swift -I %t \
|
||||||
|
// RUN: -disable-print-missing-imports-in-module-interface
|
||||||
|
// RUN: not %target-swift-typecheck-module-from-interface(%t/UsesAliasesImplementationOnlyImport.swiftinterface) -I %t
|
||||||
|
|
||||||
//--- Original.swift
|
//--- Original.swift
|
||||||
|
|
||||||
@@ -47,23 +60,28 @@ public typealias WrapperAlias = Wrapper
|
|||||||
|
|
||||||
import Aliases
|
import Aliases
|
||||||
|
|
||||||
// expected-warning@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported by this file; this is an error in Swift 6}}
|
// expected-warning@+2 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}}
|
||||||
public class InheritsFromClazzAlias: ClazzAlias {}
|
public class InheritsFromClazzAlias: ClazzAlias {}
|
||||||
|
|
||||||
@inlinable public func inlinableFunc() {
|
@inlinable public func inlinableFunc() {
|
||||||
// expected-warning@+1 {{'StructAlias' aliases 'Original.Struct' and cannot be used in an '@inlinable' function because 'Original' was not imported by this file; this is an error in Swift 6}}
|
// expected-warning@+2 {{'StructAlias' aliases 'Original.Struct' and cannot be used in an '@inlinable' function because 'Original' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}}
|
||||||
_ = StructAlias.self
|
_ = StructAlias.self
|
||||||
}
|
}
|
||||||
|
|
||||||
// expected-warning@+1 {{'ProtoAlias' aliases 'Original.Proto' and cannot be used here because 'Original' was not imported by this file; this is an error in Swift 6}}
|
// expected-warning@+2 {{'ProtoAlias' aliases 'Original.Proto' and cannot be used here because 'Original' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}}
|
||||||
public func takesGeneric<T: ProtoAlias>(_ t: T) {}
|
public func takesGeneric<T: ProtoAlias>(_ t: T) {}
|
||||||
|
|
||||||
public struct HasMembers {
|
public struct HasMembers {
|
||||||
// expected-warning@+1 {{'WrapperAlias' aliases 'Original.Wrapper' and cannot be used as property wrapper here because 'Original' was not imported by this file; this is an error in Swift 6}}
|
// expected-warning@+2 {{'WrapperAlias' aliases 'Original.Wrapper' and cannot be used as property wrapper here because 'Original' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}}
|
||||||
@WrapperAlias public var wrapped: Int
|
@WrapperAlias public var wrapped: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// expected-warning@+1 {{'StructAlias' aliases 'Original.Struct' and cannot be used in an extension with public or '@usableFromInline' members because 'Original' was not imported by this file; this is an error in Swift 6}}
|
// expected-warning@+2 {{'StructAlias' aliases 'Original.Struct' and cannot be used in an extension with public or '@usableFromInline' members because 'Original' was not imported by this file; this is an error in Swift 6}}
|
||||||
|
// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}}
|
||||||
extension StructAlias {
|
extension StructAlias {
|
||||||
public func someFunc() {}
|
public func someFunc() {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user