diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 50e6a465866..93934c53659 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2447,6 +2447,58 @@ bool isNonSendableExtension(const Decl *D) { bool ShouldPrintChecker::shouldPrint(const Decl *D, const PrintOptions &Options) { + // Skip constructors defined in Objective-C categories that are not + // publicly imported according to the interface type being generated + if (auto *CD = dyn_cast(D)) { + if (CD->isImplicit() && Options.IsForSwiftInterface && + Options.CurrentModule) { + // For inherited constructors, check the original declaration + auto *checkDecl = CD; + if (auto *overridden = CD->getOverriddenDecl()) { + checkDecl = overridden; + } + auto definingModule = checkDecl->getModuleContext(); + // Check how the defining module is imported + if (auto *SF = CD->getDeclContext()->getParentSourceFile()) { + // Don't check import status for self-imports + if (definingModule != SF->getParentModule()) { + auto restrictedKind = SF->getRestrictedImportKind(definingModule); + switch (restrictedKind) { + // MissingImport and ImplementationOnly: skip in all interfaces + case RestrictedImportKind::MissingImport: + case RestrictedImportKind::ImplementationOnly: + return false; + // SPIOnly: skip in public interfaces + case RestrictedImportKind::SPIOnly: + if (Options.printPublicInterface()) + return false; + break; + case RestrictedImportKind::None: + break; + } + // Check access level + if (auto importAccess = SF->getImportAccessLevel(definingModule)) { + auto accessLevel = importAccess->accessLevel; + switch (accessLevel) { + // Internal and below: skip in all interfaces + case AccessLevel::Private: + case AccessLevel::FilePrivate: + case AccessLevel::Internal: + return false; + // Package: skip in non-package interfaces only + case AccessLevel::Package: + if (!Options.printPackageInterface()) + return false; + break; + default: + break; + } + } + } + } + } + } + if (auto *ED = dyn_cast(D)) { if (Options.printExtensionContentAsMembers(ED)) return false; diff --git a/test/ModuleInterface/restricted-import-inherited-init.swift b/test/ModuleInterface/restricted-import-inherited-init.swift new file mode 100644 index 00000000000..61a3c6c638e --- /dev/null +++ b/test/ModuleInterface/restricted-import-inherited-init.swift @@ -0,0 +1,139 @@ +// REQUIRES: OS=macosx +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/Inputs/implementation-only-init +// RUN: split-file %s %t + +// Test with 'internal import' syntax +// RUN: %target-swift-frontend -emit-module %t/test.swift -module-name Client -enable-library-evolution -swift-version 6 -I %t/Inputs/implementation-only-init -emit-module-interface-path %t/Client.swiftinterface -emit-private-module-interface-path %t/Client.private.swiftinterface + +// RUN: %FileCheck %s -check-prefix=CHECK < %t/Client.private.swiftinterface +// RUN: %FileCheck %s -check-prefix=CHECK-PUBLIC < %t/Client.swiftinterface + +// Test with '@_implementationOnly import' syntax +// RUN: %target-swift-frontend -emit-module %t/test2.swift -module-name Client2 -enable-library-evolution -swift-version 6 -I %t/Inputs/implementation-only-init -emit-module-interface-path %t/Client2.swiftinterface -emit-private-module-interface-path %t/Client2.private.swiftinterface + +// RUN: %FileCheck %s -check-prefix=CHECK < %t/Client2.private.swiftinterface + +// Test with '@_spiOnly import' syntax +// RUN: %target-swift-frontend -emit-module %t/test3.swift -module-name Client3 -enable-library-evolution -swift-version 6 -I %t/Inputs/implementation-only-init -emit-module-interface-path %t/Client3.swiftinterface -emit-private-module-interface-path %t/Client3.private.swiftinterface -experimental-spi-only-imports + +// RUN: %FileCheck %s -check-prefix=CHECK-SPI-PRIVATE < %t/Client3.private.swiftinterface +// RUN: %FileCheck %s -check-prefix=CHECK-SPI-PUBLIC < %t/Client3.swiftinterface + +// Test with 'package import' syntax +// RUN: %target-swift-frontend -emit-module %t/test4.swift -module-name Client4 -enable-library-evolution -swift-version 6 -I %t/Inputs/implementation-only-init -emit-module-interface-path %t/Client4.swiftinterface -emit-private-module-interface-path %t/Client4.private.swiftinterface -emit-package-module-interface-path %t/Client4.package.swiftinterface -package-name MyPackage + +// RUN: %FileCheck %s -check-prefix=CHECK-PRIVATE < %t/Client4.private.swiftinterface +// RUN: %FileCheck %s -check-prefix=CHECK-PACKAGE < %t/Client4.package.swiftinterface + +// Test with 'private import' syntax +// RUN: %target-swift-frontend -emit-module %t/test5.swift -module-name Client5 -enable-library-evolution -swift-version 6 -I %t/Inputs/implementation-only-init -emit-module-interface-path %t/Client5.swiftinterface -emit-private-module-interface-path %t/Client5.private.swiftinterface + +// RUN: %FileCheck %s -check-prefix=CHECK-PRIVATE < %t/Client5.private.swiftinterface + +// CHECK: import BaseModule +// CHECK-NOT: import ExtensionModule +// CHECK: public class DerivedClass +// CHECK-NOT: init(handler: +// CHECK-NOT: init(nonnullHandler: +// CHECK-NOT: ExtensionType + +// CHECK-PUBLIC: import BaseModule +// CHECK-PUBLIC-NOT: import ExtensionModule +// CHECK-PUBLIC: public class DerivedClass +// CHECK-PUBLIC-NOT: init(handler: +// CHECK-PUBLIC-NOT: init(nonnullHandler: +// CHECK-PUBLIC-NOT: ExtensionType + +// CHECK-SPI-PRIVATE: import BaseModule +// CHECK-SPI-PRIVATE: @_spiOnly import ExtensionModule +// CHECK-SPI-PRIVATE: public class DerivedClass +// CHECK-SPI-PRIVATE: init!(handler: +// CHECK-SPI-PRIVATE: init!(nonnullHandler +// CHECK-SPI-PRIVATE: ExtensionType + +// CHECK-SPI-PUBLIC: import BaseModule +// CHECK-SPI-PUBLIC-NOT: @_spiOnly import ExtensionModule +// CHECK-SPI-PUBLIC-NOT: import ExtensionModule +// CHECK-SPI-PUBLIC: public class DerivedClass +// CHECK-SPI-PUBLIC-NOT: init(handler: +// CHECK-SPI-PUBLIC-NOT: init(nonnullHandler: +// CHECK-SPI-PUBLIC-NOT: ExtensionType + +// CHECK-PACKAGE-PRIVATE: import BaseModule +// CHECK-PACKAGE-PRIVATE-NOT: import ExtensionModule +// CHECK-PACKAGE-PRIVATE: public class DerivedClass +// CHECK-PACKAGE-PRIVATE-NOT: init(handler: +// CHECK-PACKAGE-PRIVATE-NOT: init(nonnullHandler: +// CHECK-PACKAGE-PRIVATE-NOT: ExtensionType + +// CHECK-PACKAGE: import BaseModule +// CHECK-PACKAGE: package import ExtensionModule +// CHECK-PACKAGE: public class DerivedClass +// CHECK-PACKAGE: init!(handler: +// CHECK-PACKAGE: init!(nonnullHandler +// CHECK-PACKAGE: ExtensionType + +// CHECK-PRIVATE: import BaseModule +// CHECK-PRIVATE-NOT: import ExtensionModule +// CHECK-PRIVATE: public class DerivedClass +// CHECK-PRIVATE-NOT: init(handler: +// CHECK-PRIVATE-NOT: init(nonnullHandler: +// CHECK-PRIVATE-NOT: ExtensionType + +//--- Inputs/implementation-only-init/Base.h +@import Foundation; +@interface BaseClass : NSObject +- (instancetype)initWithInfo:(id)info responder:(id)responder; +@end + +//--- Inputs/implementation-only-init/module.modulemap +module BaseModule { + header "Base.h" + export * +} + +module ExtensionModule { + header "Extension.h" + export * +} + +//--- Inputs/implementation-only-init/Extension.h +@import Foundation; +#import "Base.h" +@interface ExtensionType : NSObject +@end +@interface BaseClass (Extension) +- (instancetype)initWithHandler:(ExtensionType *)handler responder:(id)responder; +- (instancetype)initWithNonnullHandler:(ExtensionType * _Nonnull)handler; +@end + +//--- test.swift +import BaseModule +internal import ExtensionModule +public class DerivedClass : BaseClass { +} + +//--- test2.swift +import BaseModule +@_implementationOnly import ExtensionModule +public class DerivedClass : BaseClass { +} + +//--- test3.swift +import BaseModule +@_spiOnly import ExtensionModule +public class DerivedClass : BaseClass { +} + +//--- test4.swift +import BaseModule +package import ExtensionModule +public class DerivedClass : BaseClass { +} + +//--- test5.swift +import BaseModule +private import ExtensionModule +public class DerivedClass : BaseClass { +}