Files
swift-mirror/test/decl/protocol/conforms/nscoding.swift
Jordan Rose 5c1967397b Update and re-enable the diagnostics for unstable runtime names.
This time, the warnings only fire when the class in question directly
conforms to NSCoding. This avoids warning on cases where the user has
subclassed something like, oh, UIViewController, and has no intention
of writing it to a persistent file.

This also removes the warning for generic classes that conform to
NSCoding, for simplicity's sake. That means
'@NSKeyedArchiverEncodeNonGenericSubclassesOnly' is also being
removed.

Actually archiving a class with an unstable mangled name is still
considered problematic, but the compiler shouldn't emit diagnostics
unless it can be sure they are relevant.

rdar://problem/32314195
2017-06-05 17:32:26 -07:00

160 lines
7.3 KiB
Swift

// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -swift-version 4 %s -verify
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -swift-version 4 %s -disable-nskeyedarchiver-diagnostics 2>&1 | %FileCheck -check-prefix CHECK-NO-DIAGS %s
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -swift-version 4 %s -dump-ast 2> %t.ast
// RUN: %FileCheck %s < %t.ast
// REQUIRES: objc_interop
// CHECK-NO-DIAGS-NOT: NSCoding
// CHECK-NO-DIAGS-NOT: unstable
import Foundation
// Top-level classes
// CHECK-NOT: class_decl "CodingA"{{.*}}@_staticInitializeObjCMetadata
class CodingA : NSObject, NSCoding {
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
} // okay
// Nested classes
extension CodingA {
// CHECK: class_decl "NestedA"{{.*}}@_staticInitializeObjCMetadata
class NestedA : NSObject, NSCoding { // expected-error{{nested class 'CodingA.NestedA' has an unstable name when archiving via 'NSCoding'}}
// expected-note@-1{{for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name}}{{3-3=@objc(_TtCC8nscoding7CodingA7NestedA)}}
// expected-note@-2{{for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name}}{{3-3=@objc(<#prefixed Objective-C class name#>)}}
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
class NestedB : NSObject {
// expected-note@-1{{for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name}}{{3-3=@objc(_TtCC8nscoding7CodingA7NestedB)}}
// expected-note@-2{{for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name}}{{3-3=@objc(<#prefixed Objective-C class name#>)}}
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
// CHECK: class_decl "NestedC"{{.*}}@_staticInitializeObjCMetadata
@objc(CodingA_NestedC)
class NestedC : NSObject, NSCoding {
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
// CHECK: class_decl "NestedD"{{.*}}@_staticInitializeObjCMetadata
@objc(CodingA_NestedD)
class NestedD : NSObject {
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
}
extension CodingA.NestedB: NSCoding { // expected-error{{nested class 'CodingA.NestedB' has an unstable name when archiving via 'NSCoding'}}
}
extension CodingA.NestedD: NSCoding { // okay
}
// Generic classes
// CHECK-NOT: class_decl "CodingB"{{.*}}@_staticInitializeObjCMetadata
class CodingB<T> : NSObject, NSCoding {
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
extension CodingB {
class NestedA : NSObject, NSCoding {
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
}
// Fileprivate classes.
// CHECK-NOT: class_decl "CodingC"{{.*}}@_staticInitializeObjCMetadata
fileprivate class CodingC : NSObject, NSCoding { // expected-error{{fileprivate class 'CodingC' has an unstable name when archiving via 'NSCoding'}}
// expected-note@-1{{for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name}}{{1-1=@objc(_TtC8nscodingP33_0B4E7641C0BD1F170280EEDD0D0C1F6C7CodingC)}}
// expected-note@-2{{for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name}}{{1-1=@objc(<#prefixed Objective-C class name#>)}}
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
// Private classes
private class CodingD : NSObject, NSCoding { // expected-error{{private class 'CodingD' has an unstable name when archiving via 'NSCoding'}}
// expected-note@-1{{for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name}}{{1-1=@objc(_TtC8nscodingP33_0B4E7641C0BD1F170280EEDD0D0C1F6C7CodingD)}}
// expected-note@-2{{for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name}}{{1-1=@objc(<#prefixed Objective-C class name#>)}}
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
// Local classes.
func someFunction() {
class LocalCoding : NSObject, NSCoding { // expected-error{{local class 'LocalCoding' has an unstable name when archiving via 'NSCoding'}}
// expected-note@-1{{for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name}}{{3-3=@objc(_TtCF8nscoding12someFunctionFT_T_L_11LocalCoding)}}
// expected-note@-2{{for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name}}{{3-3=@objc(<#prefixed Objective-C class name#>)}}
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
}
// Inherited conformances.
// CHECK-NOT: class_decl "CodingE"{{.*}}@_staticInitializeObjCMetadata
class CodingE<T> : CodingB<T> {
required init(coder: NSCoder) { super.init(coder: coder) }
override func encode(coder: NSCoder) { }
}
// @objc suppressions
@objc(TheCodingF)
fileprivate class CodingF : NSObject, NSCoding {
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
@objc(TheCodingG)
private class CodingG : NSObject, NSCoding {
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
extension CodingB {
// CHECK-NOT: class_decl "GenericViaScope"{{.*}}@_staticInitializeObjCMetadata
@objc(GenericViaScope) // expected-error {{generic subclasses of '@objc' classes cannot have an explicit '@objc' because they are not directly visible from Objective-C}}
class GenericViaScope : NSObject { }
}
// Inference of @_staticInitializeObjCMetadata.
// CHECK-NOT: class_decl "SubclassOfCodingA"{{.*}}@_staticInitializeObjCMetadata
class SubclassOfCodingA : CodingA { }
// CHECK: class_decl "SubclassOfCodingE"{{.*}}@_staticInitializeObjCMetadata
class SubclassOfCodingE : CodingE<Int> { }
// Do not warn when simply inheriting from classes that conform to NSCoding.
// The subclass may never be serialized. But do still infer static
// initialization, just in case.
// CHECK-NOT: class_decl "PrivateSubclassOfCodingA"{{.*}}@_staticInitializeObjCMetadata
private class PrivateSubclassOfCodingA : CodingA { }
// CHECK: class_decl "PrivateSubclassOfCodingE"{{.*}}@_staticInitializeObjCMetadata
private class PrivateSubclassOfCodingE : CodingE<Int> { }
// But do warn when inherited through a protocol.
protocol AlsoNSCoding : NSCoding {}
private class CodingH : NSObject, AlsoNSCoding { // expected-error{{private class 'CodingH' has an unstable name when archiving via 'NSCoding'}}
// expected-note@-1{{for compatibility with existing archives, use '@objc' to record the Swift 3 runtime name}}{{1-1=@objc(_TtC8nscodingP33_0B4E7641C0BD1F170280EEDD0D0C1F6C7CodingH)}}
// expected-note@-2{{for new classes, use '@objc' to specify a unique, prefixed Objective-C runtime name}}{{1-1=@objc(<#prefixed Objective-C class name#>)}}
required init(coder: NSCoder) { }
func encode(coder: NSCoder) { }
}
@NSKeyedArchiverClassName( "abc" ) // expected-error {{@NSKeyedArchiverClassName has been removed; use @objc instead}} {{2-26=objc}} {{28-29=}} {{32-33=}}
class OldArchiverAttribute: NSObject {}
@NSKeyedArchiverEncodeNonGenericSubclassesOnly // expected-error {{@NSKeyedArchiverEncodeNonGenericSubclassesOnly is no longer necessary}} {{1-48=}}
class OldArchiverAttributeGeneric<T>: NSObject {}
// Don't allow one to write @_staticInitializeObjCMetadata!
@_staticInitializeObjCMetadata // expected-error{{unknown attribute '_staticInitializeObjCMetadata'}}
class DontAllowStaticInits { }