mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Require objcImplementation members to avoid vtable
They either must be @objc dynamic (the dynamic is implicit) or final.
This commit is contained in:
@@ -1512,6 +1512,18 @@ NOTE(attr_objc_implementation_fixit_remove_category_name,none,
|
||||
"remove arguments to implement the main '@interface' for this class",
|
||||
())
|
||||
|
||||
ERROR(member_of_objc_implementation_not_objc_or_final,none,
|
||||
"%0 %1 does not match any %0 declared in the headers for %2; did you use "
|
||||
"the %0's Swift name?",
|
||||
(DescriptiveDeclKind, ValueDecl *, ValueDecl *))
|
||||
NOTE(fixit_add_objc_for_objc_implementation,none,
|
||||
"add '@objc' to define an Objective-C-compatible %0 not declared in "
|
||||
"the header",
|
||||
(DescriptiveDeclKind))
|
||||
NOTE(fixit_add_final_for_objc_implementation,none,
|
||||
"add 'final' to define a Swift %0 that cannot be overridden",
|
||||
(DescriptiveDeclKind))
|
||||
|
||||
ERROR(cdecl_not_at_top_level,none,
|
||||
"@_cdecl can only be applied to global functions", ())
|
||||
ERROR(cdecl_empty_name,none,
|
||||
|
||||
@@ -987,6 +987,12 @@ IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
|
||||
if (isa<ExtensionDecl>(dc) && dc->getSelfClassDecl())
|
||||
return true;
|
||||
|
||||
// @objc declarations in @_objcImplementation extensions are implicitly
|
||||
// dynamic.
|
||||
if (auto ED = dyn_cast_or_null<ExtensionDecl>(dc->getAsDecl()))
|
||||
if (ED->isObjCImplementation())
|
||||
return true;
|
||||
|
||||
// If any of the declarations overridden by this declaration are dynamic
|
||||
// or were imported from Objective-C, this declaration is dynamic.
|
||||
// Don't do this if the declaration is not exposed to Objective-C; that's
|
||||
|
||||
@@ -1213,6 +1213,29 @@ static void checkDynamicSelfType(ValueDecl *decl, Type type) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that, if this declaration is a member of an `@_objcImplementation`
|
||||
/// extension, it is either `final` or `@objc` (which may have been inferred by
|
||||
/// checking whether it shadows an imported declaration).
|
||||
static void checkObjCImplementationMemberAvoidsVTable(ValueDecl *VD) {
|
||||
auto ED = dyn_cast<ExtensionDecl>(VD->getDeclContext());
|
||||
if (!ED || !ED->isObjCImplementation()) return;
|
||||
|
||||
if (VD->isSemanticallyFinal() || VD->isObjC()) return;
|
||||
|
||||
auto &diags = VD->getASTContext().Diags;
|
||||
diags.diagnose(VD, diag::member_of_objc_implementation_not_objc_or_final,
|
||||
VD->getDescriptiveKind(), VD, ED->getExtendedNominal());
|
||||
|
||||
if (canBeRepresentedInObjC(VD))
|
||||
diags.diagnose(VD, diag::fixit_add_objc_for_objc_implementation,
|
||||
VD->getDescriptiveKind())
|
||||
.fixItInsert(VD->getAttributeInsertionLoc(false), "@objc ");
|
||||
|
||||
diags.diagnose(VD, diag::fixit_add_final_for_objc_implementation,
|
||||
VD->getDescriptiveKind())
|
||||
.fixItInsert(VD->getAttributeInsertionLoc(true), "final ");
|
||||
}
|
||||
|
||||
/// Build a default initializer string for the given pattern.
|
||||
///
|
||||
/// This string is suitable for display in diagnostics.
|
||||
@@ -1836,6 +1859,10 @@ public:
|
||||
(void) VD->isObjC();
|
||||
(void) VD->isDynamic();
|
||||
|
||||
// If this is in an `@_objcImplementation` extension, check whether it's
|
||||
// valid there.
|
||||
checkObjCImplementationMemberAvoidsVTable(VD);
|
||||
|
||||
// Check for actor isolation of top-level and local declarations.
|
||||
// Declarations inside types are handled in checkConformancesInContext()
|
||||
// to avoid cycles involving associated type inference.
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
@_objcImplementation extension ObjCClass {
|
||||
func method(fromHeader1: CInt) {
|
||||
// FIXME: OK, provides an implementation for the header's method.
|
||||
// expected-error@-2 {{instance method 'method(fromHeader1:)' does not match any instance method declared in the headers for 'ObjCClass'; did you use the instance method's Swift name?}}
|
||||
// expected-note@-3 {{add '@objc' to define an Objective-C-compatible instance method not declared in the header}} {{3-3=@objc }}
|
||||
// expected-note@-4 {{add 'final' to define a Swift instance method that cannot be overridden}} {{3-3=final }}
|
||||
}
|
||||
|
||||
@objc func method(fromHeader2: CInt) {
|
||||
@@ -13,6 +16,9 @@
|
||||
|
||||
func categoryMethod(fromHeader3: CInt) {
|
||||
// FIXME: Should complain about the wrong category
|
||||
// expected-error@-2 {{instance method 'categoryMethod(fromHeader3:)' does not match any instance method declared in the headers for 'ObjCClass'; did you use the instance method's Swift name?}}
|
||||
// expected-note@-3 {{add '@objc' to define an Objective-C-compatible instance method not declared in the header}} {{3-3=@objc }}
|
||||
// expected-note@-4 {{add 'final' to define a Swift instance method that cannot be overridden}} {{3-3=final }}
|
||||
}
|
||||
|
||||
@objc fileprivate func methodNot(fromHeader1: CInt) {
|
||||
@@ -24,7 +30,9 @@
|
||||
}
|
||||
|
||||
func methodNot(fromHeader3: CInt) {
|
||||
// FIXME: Should complain about unmatched, un-attributed method
|
||||
// expected-error@-1 {{instance method 'methodNot(fromHeader3:)' does not match any instance method declared in the headers for 'ObjCClass'; did you use the instance method's Swift name?}}
|
||||
// expected-note@-2 {{add '@objc' to define an Objective-C-compatible instance method not declared in the header}} {{3-3=@objc }}
|
||||
// expected-note@-3 {{add 'final' to define a Swift instance method that cannot be overridden}} {{3-3=final }}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,10 +40,19 @@
|
||||
@_objcImplementation(PresentAdditions) extension ObjCClass {
|
||||
func method(fromHeader3: CInt) {
|
||||
// FIXME: Should complain about wrong category
|
||||
// expected-error@-2 {{instance method 'method(fromHeader3:)' does not match any instance method declared in the headers for 'ObjCClass'; did you use the instance method's Swift name?}}
|
||||
// expected-note@-3 {{add '@objc' to define an Objective-C-compatible instance method not declared in the header}} {{3-3=@objc }}
|
||||
// expected-note@-4 {{add 'final' to define a Swift instance method that cannot be overridden}} {{3-3=final }}
|
||||
}
|
||||
|
||||
func categoryMethod(fromHeader1: CInt) {
|
||||
// FIXME: OK, provides an implementation for the header's method.
|
||||
// expected-error@-2 {{instance method 'categoryMethod(fromHeader1:)' does not match any instance method declared in the headers for 'ObjCClass'; did you use the instance method's Swift name?}}
|
||||
// expected-note@-3 {{add '@objc' to define an Objective-C-compatible instance method not declared in the header}} {{3-3=@objc }}
|
||||
// expected-note@-4 {{add 'final' to define a Swift instance method that cannot be overridden}} {{3-3=final }}
|
||||
}
|
||||
|
||||
@objc func categoryMethod(fromHeader2: CInt) {
|
||||
// OK, provides an implementation for the header's method.
|
||||
}
|
||||
|
||||
@@ -48,7 +65,9 @@
|
||||
}
|
||||
|
||||
func categoryMethodNot(fromHeader3: CInt) {
|
||||
// FIXME: Should complain about unmatched, un-attributed method
|
||||
// expected-error@-1 {{instance method 'categoryMethodNot(fromHeader3:)' does not match any instance method declared in the headers for 'ObjCClass'; did you use the instance method's Swift name?}}
|
||||
// expected-note@-2 {{add '@objc' to define an Objective-C-compatible instance method not declared in the header}} {{3-3=@objc }}
|
||||
// expected-note@-3 {{add 'final' to define a Swift instance method that cannot be overridden}} {{3-3=final }}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,3 +91,23 @@
|
||||
|
||||
@_objcImplementation(WTF) extension SwiftClass {} // expected
|
||||
// expected-error@-1 {{'@_objcImplementation' cannot be used to extend class 'SwiftClass' because it was defined by a Swift 'class' declaration, not an imported Objective-C '@interface' declaration}} {{1-27=}}
|
||||
|
||||
func usesAreNotAmbiguous(obj: ObjCClass) {
|
||||
obj.method(fromHeader1: 1)
|
||||
obj.method(fromHeader2: 2)
|
||||
obj.method(fromHeader3: 3)
|
||||
obj.method(fromHeader4: 4)
|
||||
|
||||
obj.methodNot(fromHeader1: 1)
|
||||
obj.methodNot(fromHeader2: 2)
|
||||
obj.methodNot(fromHeader3: 3)
|
||||
|
||||
obj.categoryMethod(fromHeader1: 1)
|
||||
obj.categoryMethod(fromHeader2: 2)
|
||||
obj.categoryMethod(fromHeader3: 3)
|
||||
obj.categoryMethod(fromHeader4: 4)
|
||||
|
||||
obj.categoryMethodNot(fromHeader1: 1)
|
||||
obj.categoryMethodNot(fromHeader2: 2)
|
||||
obj.categoryMethodNot(fromHeader3: 3)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user