Merge pull request #60659 from xymus/print-missing-imports

[ModuleInterface] Print missing imports in swiftinterface
This commit is contained in:
Alexis Laferrière
2022-08-23 09:47:25 -07:00
committed by GitHub
12 changed files with 111 additions and 5 deletions

View File

@@ -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))

View File

@@ -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 {

View File

@@ -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.
/// ///

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 :

View File

@@ -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;
} }

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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() {}
} }