[ObjCInterop] Implement @ObjCSignatureOverride
This annotation leads to conflicting overloads error supression,
in case where several function with the same argument types,
but different argument names are inherited from ObjC class.
We need to implement it in both K1 and K2 to make the IDE experience
better.
But the annotation itself wouldn't be available in K1.
^KT-61323
This commit is contained in:
committed by
Space Team
parent
77eee0d3fc
commit
6e8a7d4662
+9
@@ -90,6 +90,15 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
||||
"Can't refer to forward declaration ''{0}'' from class literal",
|
||||
Renderers.RENDER_TYPE
|
||||
)
|
||||
put(
|
||||
ErrorsNative.CONFLICTING_OBJC_OVERLOADS,
|
||||
"Conflicting overloads: {0}. Add @ObjCSignatureOverride to allow collision for functions inherited from Objective-C.",
|
||||
CommonRenderers.commaSeparated(Renderers.FQ_NAMES_IN_TYPES)
|
||||
)
|
||||
put(
|
||||
ErrorsNative.INAPPLICABLE_OBJC_OVERRIDE,
|
||||
"@ObjCSignatureOverride is only allowed on functions inherited from Objective-C.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@ object ErrorsNative {
|
||||
val FORWARD_DECLARATION_AS_REIFIED_TYPE_ARGUMENT = DiagnosticFactory1.create<PsiElement, KotlinType>(Severity.ERROR)
|
||||
@JvmField
|
||||
val FORWARD_DECLARATION_AS_CLASS_LITERAL = DiagnosticFactory1.create<PsiElement, KotlinType>(Severity.ERROR)
|
||||
@JvmField
|
||||
val CONFLICTING_OBJC_OVERLOADS = DiagnosticFactory1.create<PsiElement, Collection<DeclarationDescriptor>>(Severity.ERROR)
|
||||
@JvmField
|
||||
val INAPPLICABLE_OBJC_OVERRIDE = DiagnosticFactory0.create<PsiElement>(Severity.ERROR)
|
||||
|
||||
init {
|
||||
Errors.Initializer.initializeFactoryNames(ErrorsNative::class.java)
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.konan.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
|
||||
import org.jetbrains.kotlin.ir.objcinterop.getObjCMethodInfo
|
||||
import org.jetbrains.kotlin.name.NativeStandardInteropNames.Annotations.objCSignatureOverrideClassId
|
||||
import org.jetbrains.kotlin.resolve.ConflictingOverloadsDispatcher
|
||||
|
||||
/**
|
||||
* This function basically checks that these two functions have different objective-C signature.
|
||||
*
|
||||
* This signature consists of function name and parameter names except first.
|
||||
*
|
||||
* So we ignore the first parameter name, but check others
|
||||
*/
|
||||
private fun FunctionDescriptor.hasDifferentParameterNames(other: FunctionDescriptor) : Boolean {
|
||||
return valueParameters.drop(1).map { it.name } != other.valueParameters.drop(1).map { it.name }
|
||||
}
|
||||
|
||||
object NativeConflictingOverloadsDispatcher : ConflictingOverloadsDispatcher {
|
||||
override fun getDiagnostic(
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
declaration: DeclarationDescriptor,
|
||||
redeclarations: Collection<DeclarationDescriptor>
|
||||
): DiagnosticFactory1<PsiElement, Collection<DeclarationDescriptor>>? {
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ObjCSignatureOverrideAnnotation)) {
|
||||
if (declaration is FunctionDescriptor && redeclarations.all { it is FunctionDescriptor }) {
|
||||
if (declaration.getObjCMethodInfo() != null && redeclarations.all { (it as FunctionDescriptor).getObjCMethodInfo() != null }) {
|
||||
if (redeclarations.all { it === declaration || (it as FunctionDescriptor).hasDifferentParameterNames(declaration) }) {
|
||||
if (declaration.annotations.hasAnnotation(objCSignatureOverrideClassId.asSingleFqName())) {
|
||||
return null
|
||||
} else {
|
||||
return ErrorsNative.CONFLICTING_OBJC_OVERLOADS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ConflictingOverloadsDispatcher.Default.getDiagnostic(languageVersionSettings, declaration, redeclarations)
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.konan.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.objcinterop.getObjCMethodInfo
|
||||
import org.jetbrains.kotlin.name.NativeStandardInteropNames.Annotations.objCSignatureOverrideClassId
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
|
||||
|
||||
object NativeObjcOverrideApplicabilityChecker : DeclarationChecker {
|
||||
override fun check(
|
||||
declaration: KtDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
context: DeclarationCheckerContext,
|
||||
) {
|
||||
if (descriptor is FunctionDescriptor) {
|
||||
val annotation = descriptor.annotations.findAnnotation(objCSignatureOverrideClassId.asSingleFqName()) ?: return
|
||||
if (descriptor.getObjCMethodInfo() == null) {
|
||||
context.trace.report(ErrorsNative.INAPPLICABLE_OBJC_OVERRIDE.on(DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: declaration))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -30,6 +30,7 @@ object NativePlatformConfigurator : PlatformConfiguratorBase(
|
||||
NativeObjCNameChecker, NativeObjCNameOverridesChecker,
|
||||
NativeObjCRefinementChecker, NativeObjCRefinementAnnotationChecker,
|
||||
NativeObjCRefinementOverridesChecker, NativeHiddenFromObjCInheritanceChecker,
|
||||
NativeObjcOverrideApplicabilityChecker,
|
||||
),
|
||||
platformSpecificCastChecker = NativePlatformSpecificCastChecker
|
||||
) {
|
||||
@@ -37,6 +38,7 @@ object NativePlatformConfigurator : PlatformConfiguratorBase(
|
||||
container.useInstance(NativeInliningRule)
|
||||
container.useImpl<NativeIdentifierChecker>()
|
||||
container.useImpl<NativeForwardDeclarationRttiChecker>()
|
||||
container.useInstance(NativeConflictingOverloadsDispatcher)
|
||||
}
|
||||
|
||||
override fun configureModuleDependentCheckers(container: StorageComponentContainer) {
|
||||
|
||||
Reference in New Issue
Block a user