diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt index 08295bfaf4c..504e91fc3c8 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt @@ -16,17 +16,17 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.utils.addToStdlib.safeAs object NativeObjCNameChecker : DeclarationChecker { + private val objCNameFqName = FqName("kotlin.native.ObjCName") override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { checkDeclaration(declaration, descriptor, context) - checkOverrides(declaration, descriptor, context) - checkFakeOverrides(declaration, descriptor, context) + if (descriptor is CallableMemberDescriptor) { + NativeObjCNameOverridesChecker.check(declaration, descriptor, context) + } } private fun checkDeclaration(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { @@ -84,29 +84,7 @@ object NativeObjCNameChecker : DeclarationChecker { } } - private fun checkOverrides(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { - if (descriptor !is CallableMemberDescriptor || descriptor.overriddenDescriptors.isEmpty()) return - val objCNames = descriptor.overriddenDescriptors.map { it.getFirstBaseDescriptor().getObjCNames() } - if (!objCNames.allNamesEquals()) { - val containingDeclarations = descriptor.overriddenDescriptors.map { it.containingDeclaration } - context.trace.report(ErrorsNative.INCOMPATIBLE_OBJC_NAME_OVERRIDE.on(declaration, descriptor, containingDeclarations)) - } - } - - private fun checkFakeOverrides(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { - if (descriptor !is ClassDescriptor) return - descriptor.defaultType.memberScope - .getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.Companion.ALL_NAME_FILTER) - .forEach { - if (it !is CallableMemberDescriptor || it.kind.isReal) return@forEach - checkOverrides(declaration, it, context) - } - } - - private fun CallableMemberDescriptor.getFirstBaseDescriptor(): CallableMemberDescriptor = - if (overriddenDescriptors.isEmpty()) this else overriddenDescriptors.first().getFirstBaseDescriptor() - - private class ObjCName( + class ObjCName( val annotation: AnnotationDescriptor ) { val name: String? = annotation.argumentValue("name")?.value?.safeAs()?.takeIf { it.isNotBlank() } @@ -126,20 +104,13 @@ object NativeObjCNameChecker : DeclarationChecker { private fun DeclarationDescriptor.getObjCName(): ObjCName? = annotations.findAnnotation(objCNameFqName)?.let(::ObjCName) - private fun DeclarationDescriptor.getObjCNames(): List = when (this) { + fun DeclarationDescriptor.getObjCNames(): List = when (this) { is FunctionDescriptor -> buildList { add(getObjCName()) add(extensionReceiverParameter?.getObjCName()) valueParameters.forEach { add(it.getObjCName()) } } + else -> listOf(getObjCName()) } - - private fun List>.allNamesEquals(): Boolean { - val first = this[0] - for (i in 1 until size) { - if (first != this[i]) return false - } - return true - } -} \ No newline at end of file +} diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameOverridesChecker.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameOverridesChecker.kt new file mode 100644 index 00000000000..010a15ce134 --- /dev/null +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameOverridesChecker.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2022 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.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.konan.diagnostics.NativeObjCNameChecker.getObjCNames +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.MemberScope + +object NativeObjCNameOverridesChecker : DeclarationChecker { + + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (descriptor !is ClassDescriptor) return + descriptor.defaultType.memberScope + .getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.Companion.ALL_NAME_FILTER) + .forEach { + if (it !is CallableMemberDescriptor || it.kind.isReal) return@forEach + check(declaration, it, context) + } + } + + fun check(declaration: KtDeclaration, descriptor: CallableMemberDescriptor, context: DeclarationCheckerContext) { + if (descriptor.overriddenDescriptors.isEmpty()) return + val objCNames = descriptor.overriddenDescriptors.map { it.getFirstBaseDescriptor().getObjCNames() } + if (!objCNames.allNamesEquals()) { + val containingDeclarations = descriptor.overriddenDescriptors.map { it.containingDeclaration } + context.trace.report(ErrorsNative.INCOMPATIBLE_OBJC_NAME_OVERRIDE.on(declaration, descriptor, containingDeclarations)) + } + } + + private fun CallableMemberDescriptor.getFirstBaseDescriptor(): CallableMemberDescriptor = + if (overriddenDescriptors.isEmpty()) this else overriddenDescriptors.first().getFirstBaseDescriptor() + + private fun List>.allNamesEquals(): Boolean { + val first = this[0] + for (i in 1 until size) { + if (first != this[i]) return false + } + return true + } +} diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/platform/NativePlatformConfigurator.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/platform/NativePlatformConfigurator.kt index 5e32d30b5a7..99964b61fc4 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/platform/NativePlatformConfigurator.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/platform/NativePlatformConfigurator.kt @@ -24,8 +24,9 @@ object NativePlatformConfigurator : PlatformConfiguratorBase( additionalDeclarationCheckers = listOf( NativeThrowsChecker, NativeSharedImmutableChecker, NativeTopLevelSingletonChecker, NativeThreadLocalChecker, - NativeObjCNameChecker, NativeObjCRefinementChecker, - NativeObjCRefinementAnnotationChecker, NativeObjCRefinementOverridesChecker + NativeObjCNameChecker, NativeObjCNameOverridesChecker, + NativeObjCRefinementChecker, NativeObjCRefinementAnnotationChecker, + NativeObjCRefinementOverridesChecker ) ) { override fun configureModuleComponents(container: StorageComponentContainer) {