Refactor and improve Objective-C override checks (#2907)
This commit is contained in:
committed by
GitHub
parent
73d5ac8120
commit
14fb86d487
+26
-21
@@ -147,32 +147,37 @@ class ObjCOverridabilityCondition : ExternalOverridabilityCondition {
|
|||||||
subDescriptor: CallableDescriptor,
|
subDescriptor: CallableDescriptor,
|
||||||
subClassDescriptor: ClassDescriptor?
|
subClassDescriptor: ClassDescriptor?
|
||||||
): ExternalOverridabilityCondition.Result {
|
): ExternalOverridabilityCondition.Result {
|
||||||
|
if (superDescriptor.name == subDescriptor.name) { // Slow path:
|
||||||
if (superDescriptor.name != subDescriptor.name) {
|
if (superDescriptor is FunctionDescriptor && subDescriptor is FunctionDescriptor) {
|
||||||
return ExternalOverridabilityCondition.Result.UNKNOWN
|
superDescriptor.getExternalObjCMethodInfo()?.let { superInfo ->
|
||||||
}
|
val subInfo = subDescriptor.getExternalObjCMethodInfo()
|
||||||
|
if (subInfo != null) {
|
||||||
val superClass = superDescriptor.containingDeclaration as? ClassDescriptor
|
// Overriding Objective-C method by Objective-C method in interop stubs.
|
||||||
val subClass = subDescriptor.containingDeclaration as? ClassDescriptor
|
// Don't even check method signatures:
|
||||||
|
return if (superInfo.selector == subInfo.selector) {
|
||||||
if (superClass == null || !superClass.isObjCClass() || subClass == null) {
|
ExternalOverridabilityCondition.Result.OVERRIDABLE
|
||||||
return ExternalOverridabilityCondition.Result.UNKNOWN
|
} else {
|
||||||
}
|
ExternalOverridabilityCondition.Result.INCOMPATIBLE
|
||||||
|
}
|
||||||
return if (areSelectorsEqual(superDescriptor, subDescriptor)) {
|
} else {
|
||||||
// Also check the method signatures if the subclass is user-defined:
|
// Overriding Objective-C method by Kotlin method.
|
||||||
if (subClass.isExternalObjCClass()) {
|
if (!parameterNamesMatch(superDescriptor, subDescriptor)) {
|
||||||
ExternalOverridabilityCondition.Result.OVERRIDABLE
|
return ExternalOverridabilityCondition.Result.INCOMPATIBLE
|
||||||
} else {
|
}
|
||||||
ExternalOverridabilityCondition.Result.UNKNOWN
|
}
|
||||||
|
}
|
||||||
|
} else if (superDescriptor.isExternalObjCClassProperty() && subDescriptor.isExternalObjCClassProperty()) {
|
||||||
|
return ExternalOverridabilityCondition.Result.OVERRIDABLE
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ExternalOverridabilityCondition.Result.INCOMPATIBLE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ExternalOverridabilityCondition.Result.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun areSelectorsEqual(first: CallableDescriptor, second: CallableDescriptor): Boolean {
|
private fun CallableDescriptor.isExternalObjCClassProperty() = this is PropertyDescriptor &&
|
||||||
|
(this.containingDeclaration as? ClassDescriptor)?.isExternalObjCClass() == true
|
||||||
|
|
||||||
|
private fun parameterNamesMatch(first: FunctionDescriptor, second: FunctionDescriptor): Boolean {
|
||||||
// The original Objective-C method selector is represented as
|
// The original Objective-C method selector is represented as
|
||||||
// function name and parameter names (except first).
|
// function name and parameter names (except first).
|
||||||
|
|
||||||
|
|||||||
@@ -150,12 +150,21 @@ NSObject* createNSObject() {
|
|||||||
-(instancetype _Nonnull)initWithFormat:(NSString*)format, ...;
|
-(instancetype _Nonnull)initWithFormat:(NSString*)format, ...;
|
||||||
+(instancetype _Nonnull)testVarargsWithFormat:(NSString*)format, ...;
|
+(instancetype _Nonnull)testVarargsWithFormat:(NSString*)format, ...;
|
||||||
@property NSString* formatted;
|
@property NSString* formatted;
|
||||||
|
|
||||||
|
+(NSString* _Nonnull)stringWithFormat:(NSString*)format, ...;
|
||||||
|
+(NSObject* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args;
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
@interface TestVarargs (TestVarargsExtension)
|
@interface TestVarargs (TestVarargsExtension)
|
||||||
-(instancetype _Nonnull)initWithFormat:(NSString*)format, ...;
|
-(instancetype _Nonnull)initWithFormat:(NSString*)format, ...;
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
|
@interface TestVarargsSubclass : TestVarargs
|
||||||
|
// Test clashes:
|
||||||
|
-(instancetype _Nonnull)initWithFormat:(NSString*)format args:(void*)args;
|
||||||
|
+(NSString* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args;
|
||||||
|
@end;
|
||||||
|
|
||||||
@interface TestOverrideInit : NSObject
|
@interface TestOverrideInit : NSObject
|
||||||
-(instancetype)initWithValue:(int)value NS_DESIGNATED_INITIALIZER;
|
-(instancetype)initWithValue:(int)value NS_DESIGNATED_INITIALIZER;
|
||||||
+(instancetype)createWithValue:(int)value;
|
+(instancetype)createWithValue:(int)value;
|
||||||
|
|||||||
@@ -299,6 +299,14 @@ fun testVarargs() {
|
|||||||
format = "%d %d %d"
|
format = "%d %d %d"
|
||||||
).formatted
|
).formatted
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"7",
|
||||||
|
TestVarargsSubclass.stringWithFormat(
|
||||||
|
"%d",
|
||||||
|
7
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testOverrideInit() {
|
fun testOverrideInit() {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ static CustomRetainMethodsImpl* retainedCustomRetainMethodsImpl;
|
|||||||
}
|
}
|
||||||
|
|
||||||
+(instancetype _Nonnull)testVarargsWithFormat:(NSString*)format, ... {
|
+(instancetype _Nonnull)testVarargsWithFormat:(NSString*)format, ... {
|
||||||
TestVarargs* result = [[TestVarargs alloc] init];
|
TestVarargs* result = [[self alloc] init];
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
@@ -144,6 +144,29 @@ static CustomRetainMethodsImpl* retainedCustomRetainMethodsImpl;
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+(NSString* _Nonnull)stringWithFormat:(NSString*)format, ... {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
NSString* result = [[NSString alloc] initWithFormat:format arguments:args];
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
+(NSObject* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@end;
|
||||||
|
|
||||||
|
@implementation TestVarargsSubclass
|
||||||
|
-(instancetype _Nonnull)initWithFormat:(NSString*)format args:(void*)args {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
+(NSString* _Nonnull)stringWithFormat:(NSString*)format args:(void*)args {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
@end;
|
@end;
|
||||||
|
|
||||||
@implementation TestOverrideInit
|
@implementation TestOverrideInit
|
||||||
|
|||||||
Reference in New Issue
Block a user