From 0a8cefc8a528c6c62d758b9894912aacdda960c1 Mon Sep 17 00:00:00 2001 From: Rick Clephas Date: Fri, 19 Aug 2022 16:46:36 +0200 Subject: [PATCH] [FIR] Add NativeObjCRefinement checkers --- ...rontendNativeDiagnosticsTestGenerated.java | 6 + ...DiagnosticsWithLightTreeTestGenerated.java | 6 + .../diagnostics/FirNativeDiagnosticsList.kt | 10 +- .../diagnostics/native/FirNativeErrors.kt | 4 + .../native/FirNativeErrorsDefaultMessages.kt | 14 ++ ...irNativeObjCRefinementAnnotationChecker.kt | 56 +++++++ .../FirNativeObjCRefinementChecker.kt | 64 ++++++++ ...FirNativeObjCRefinementOverridesChecker.kt | 138 ++++++++++++++++++ .../checkers/NativeDeclarationCheckers.kt | 20 ++- .../diagnostics/nativeTests/objCRefinement.kt | 1 + 10 files changed, 315 insertions(+), 4 deletions(-) create mode 100644 compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementAnnotationChecker.kt create mode 100644 compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt create mode 100644 compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java index a99bb5d6fde..6dac7c47028 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java @@ -36,6 +36,12 @@ public class FirOldFrontendNativeDiagnosticsTestGenerated extends AbstractFirNat runTest("compiler/testData/diagnostics/nativeTests/objCName.kt"); } + @Test + @TestMetadata("objCRefinement.kt") + public void testObjCRefinement() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/objCRefinement.kt"); + } + @Test @TestMetadata("sharedImmutable.kt") public void testSharedImmutable() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java index 735053a2755..ee59ab2c9b7 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java @@ -36,6 +36,12 @@ public class FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated extends A runTest("compiler/testData/diagnostics/nativeTests/objCName.kt"); } + @Test + @TestMetadata("objCRefinement.kt") + public void testObjCRefinement() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/objCRefinement.kt"); + } + @Test @TestMetadata("sharedImmutable.kt") public void testSharedImmutable() throws Exception { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt index 9c26a1c5779..14e26bd1807 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt @@ -10,6 +10,8 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.PositioningStrategy +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtDeclaration @@ -39,5 +41,11 @@ object NATIVE_DIAGNOSTICS_LIST : DiagnosticList("FirNativeErrors") { ) { parameter("message") } + val REDUNDANT_SWIFT_REFINEMENT by error() + val INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE by error { + parameter>("declaration") + parameter>("containingClasses") + } + val INVALID_OBJC_REFINEMENT_TARGETS by error() } -} \ No newline at end of file +} diff --git a/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt b/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt index acfce887145..df882cf9086 100644 --- a/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt +++ b/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.diagnostics.* import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory import org.jetbrains.kotlin.fir.analysis.diagnostics.* +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtDeclaration @@ -32,6 +33,9 @@ object FirNativeErrors { val INAPPLICABLE_THREAD_LOCAL by error0() val INAPPLICABLE_THREAD_LOCAL_TOP_LEVEL by error0() val INVALID_CHARACTERS_NATIVE by deprecationError1(ProhibitInvalidCharsInNativeIdentifiers, SourceElementPositioningStrategies.NAME_IDENTIFIER) + val REDUNDANT_SWIFT_REFINEMENT by error0() + val INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE by error2, Collection>() + val INVALID_OBJC_REFINEMENT_TARGETS by error0() init { RootDiagnosticRendererFactory.registerFactory(FirNativeErrorsDefaultMessages) diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt index 3d3d33c92b6..f87d5185ff3 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt @@ -15,10 +15,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAP import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_SHARED_IMMUTABLE_TOP_LEVEL import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_THREAD_LOCAL import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_THREAD_LOCAL_TOP_LEVEL +import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_THROWS_INHERITED import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_THROWS_OVERRIDE import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_CHARACTERS_NATIVE +import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_REFINEMENT_TARGETS import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND +import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.THROWS_LIST_EMPTY object FirNativeErrorsDefaultMessages : BaseDiagnosticRendererFactory() { @@ -41,6 +44,17 @@ object FirNativeErrorsDefaultMessages : BaseDiagnosticRendererFactory() { ) map.put(INAPPLICABLE_THREAD_LOCAL_TOP_LEVEL, "@ThreadLocal is applicable only to top level declarations") map.put(INVALID_CHARACTERS_NATIVE, "Name {0}", TO_STRING) + map.put(REDUNDANT_SWIFT_REFINEMENT, "An ObjC refined declaration can't also be refined in Swift") + map.put( + INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, + "Refined declaration \"{0}\" overrides declarations with different or no refinement from {1}", + SYMBOL, + SYMBOLS + ) + map.put( + INVALID_OBJC_REFINEMENT_TARGETS, + "Refines annotations are only applicable to annotations with targets FUNCTION and/or PROPERTY" + ) map.checkMissingMessages(FirNativeErrors) } diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementAnnotationChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementAnnotationChecker.kt new file mode 100644 index 00000000000..b3393ec6f7d --- /dev/null +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementAnnotationChecker.kt @@ -0,0 +1,56 @@ +/* + * 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.fir.analysis.native.checkers + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirRegularClassChecker +import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets +import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors +import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCRefinementChecker.hidesFromObjCClassId +import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCRefinementChecker.refinesInSwiftClassId +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.expressions.FirAnnotation + +object FirNativeObjCRefinementAnnotationChecker : FirRegularClassChecker() { + + private val supportedTargets = arrayOf(KotlinTarget.FUNCTION, KotlinTarget.PROPERTY) + + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.classKind != ClassKind.ANNOTATION_CLASS) return + val (objCAnnotation, swiftAnnotation) = declaration.findMetaAnnotations() + if (objCAnnotation == null && swiftAnnotation == null) return + if (objCAnnotation != null && swiftAnnotation != null) { + reporter.reportOn( + swiftAnnotation.source, + FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT, + context + ) + } + val targets = declaration.getAllowedAnnotationTargets() + val unsupportedTargets = targets - supportedTargets + if (unsupportedTargets.isNotEmpty()) { + objCAnnotation?.let { reporter.reportOn(it.source, FirNativeErrors.INVALID_OBJC_REFINEMENT_TARGETS, context) } + swiftAnnotation?.let { reporter.reportOn(it.source, FirNativeErrors.INVALID_OBJC_REFINEMENT_TARGETS, context) } + } + } + + private fun FirRegularClass.findMetaAnnotations(): Pair { + var objCAnnotation: FirAnnotation? = null + var swiftAnnotation: FirAnnotation? = null + for (annotation in annotations) { + when (annotation.toAnnotationClassId()) { + hidesFromObjCClassId -> objCAnnotation = annotation + refinesInSwiftClassId -> swiftAnnotation = annotation + } + if (objCAnnotation != null && swiftAnnotation != null) break + } + return objCAnnotation to swiftAnnotation + } +} diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt new file mode 100644 index 00000000000..58bbda5848b --- /dev/null +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementChecker.kt @@ -0,0 +1,64 @@ +/* + * 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.fir.analysis.native.checkers + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCRefinementOverridesChecker.check +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirCallableDeclarationChecker +import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope +import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.coneClassLikeType +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName + +object FirNativeObjCRefinementChecker : FirCallableDeclarationChecker() { + + val hidesFromObjCClassId = ClassId.topLevel(FqName("kotlin.native.HidesFromObjC")) + val refinesInSwiftClassId = ClassId.topLevel(FqName("kotlin.native.RefinesInSwift")) + + override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration !is FirSimpleFunction && declaration !is FirProperty) return + val (objCAnnotations, swiftAnnotations) = declaration.findRefinedAnnotations(context.session) + if (objCAnnotations.isNotEmpty() && swiftAnnotations.isNotEmpty()) { + for (swiftAnnotation in swiftAnnotations) { + reporter.reportOn(swiftAnnotation.source, REDUNDANT_SWIFT_REFINEMENT, context) + } + } + val containingClass = context.containingDeclarations.lastOrNull() as? FirClass + if (containingClass != null) { + val firTypeScope = containingClass.unsubstitutedScope(context) + check(firTypeScope, declaration.symbol, declaration, context, reporter, objCAnnotations, swiftAnnotations) + } + } + + private fun FirCallableDeclaration.findRefinedAnnotations(session: FirSession): Pair, List> { + val objCAnnotations = mutableListOf() + val swiftAnnotations = mutableListOf() + for (annotation in annotations) { + val metaAnnotations = annotation.coneClassLikeType?.lookupTag?.toSymbol(session)?.resolvedAnnotationsWithClassIds.orEmpty() + for (metaAnnotation in metaAnnotations) { + when (metaAnnotation.toAnnotationClassId()) { + hidesFromObjCClassId -> { + objCAnnotations.add(annotation) + break + } + + refinesInSwiftClassId -> { + swiftAnnotations.add(annotation) + break + } + } + } + } + return objCAnnotations to swiftAnnotations + } +} diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt new file mode 100644 index 00000000000..53a003e2783 --- /dev/null +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCRefinementOverridesChecker.kt @@ -0,0 +1,138 @@ +/* + * 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.fir.analysis.native.checkers + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker +import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope +import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE +import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCRefinementChecker.hidesFromObjCClassId +import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCRefinementChecker.refinesInSwiftClassId +import org.jetbrains.kotlin.fir.containingClass +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.coneClassLikeType +import org.jetbrains.kotlin.fir.isIntersectionOverride +import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.scopes.* +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol + +object FirNativeObjCRefinementOverridesChecker : FirClassChecker() { + + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + // We just need to check intersection overrides, all other declarations are checked by FirNativeObjCRefinementChecker + val firTypeScope = declaration.unsubstitutedScope(context) + firTypeScope.processAllFunctions { symbol -> + if (!symbol.isIntersectionOverride) return@processAllFunctions + check(firTypeScope, symbol, declaration, context, reporter, emptyList(), emptyList()) + } + firTypeScope.processAllProperties { symbol -> + if (!symbol.isIntersectionOverride) return@processAllProperties + check(firTypeScope, symbol, declaration, context, reporter, emptyList(), emptyList()) + } + } + + fun check( + firTypeScope: FirTypeScope, + memberSymbol: FirCallableSymbol<*>, + declarationToReport: FirDeclaration, + context: CheckerContext, + reporter: DiagnosticReporter, + objCAnnotations: List, + swiftAnnotations: List + ) { + val overriddenMemberSymbols = firTypeScope.getDirectOverriddenSymbols(memberSymbol) + if (overriddenMemberSymbols.isEmpty()) return + var isHiddenFromObjC = objCAnnotations.isNotEmpty() + var isRefinedInSwift = swiftAnnotations.isNotEmpty() + val supersNotHiddenFromObjC = mutableListOf>() + val supersNotRefinedInSwift = mutableListOf>() + for (symbol in overriddenMemberSymbols) { + val (superIsHiddenFromObjC, superIsRefinedInSwift) = symbol.inheritsRefinedAnnotations(context.session, firTypeScope) + if (superIsHiddenFromObjC) isHiddenFromObjC = true else supersNotHiddenFromObjC.add(symbol) + if (superIsRefinedInSwift) isRefinedInSwift = true else supersNotRefinedInSwift.add(symbol) + } + if (isHiddenFromObjC && supersNotHiddenFromObjC.isNotEmpty()) { + reporter.reportIncompatibleOverride(declarationToReport, objCAnnotations, supersNotHiddenFromObjC, context) + } + if (isRefinedInSwift && supersNotRefinedInSwift.isNotEmpty()) { + reporter.reportIncompatibleOverride(declarationToReport, swiftAnnotations, supersNotRefinedInSwift, context) + } + } + + private fun FirTypeScope.getDirectOverriddenSymbols(memberSymbol: FirCallableSymbol<*>): List> { + return when (memberSymbol) { + is FirNamedFunctionSymbol -> { + processFunctionsByName(memberSymbol.name) {} + getDirectOverriddenFunctions(memberSymbol) + } + + is FirPropertySymbol -> { + processPropertiesByName(memberSymbol.name) {} + getDirectOverriddenProperties(memberSymbol) + } + + else -> error("unexpected member kind $memberSymbol") + } + } + + private fun FirCallableSymbol<*>.inheritsRefinedAnnotations(session: FirSession, firTypeScope: FirTypeScope): Pair { + val (hasObjC, hasSwift) = hasRefinedAnnotations(session) + if (hasObjC && hasSwift) return true to true + // Note: `checkMember` requires all overridden symbols to be either refined or not refined. + val overriddenMemberSymbol = firTypeScope.getDirectOverriddenSymbols(this).firstOrNull() + ?: return hasObjC to hasSwift + val (inheritsObjC, inheritsSwift) = overriddenMemberSymbol.inheritsRefinedAnnotations(session, firTypeScope) + return (hasObjC || inheritsObjC) to (hasSwift || inheritsSwift) + } + + private fun FirCallableSymbol<*>.hasRefinedAnnotations(session: FirSession): Pair { + var hasObjC = false + var hasSwift = false + for (annotation in resolvedAnnotationsWithClassIds) { + val metaAnnotations = annotation.coneClassLikeType?.lookupTag?.toSymbol(session)?.resolvedAnnotationsWithClassIds.orEmpty() + for (metaAnnotation in metaAnnotations) { + when (metaAnnotation.toAnnotationClassId()) { + hidesFromObjCClassId -> { + hasObjC = true + break + } + + refinesInSwiftClassId -> { + hasSwift = true + break + } + } + } + if (hasObjC && hasSwift) return true to true + } + return hasObjC to hasSwift + } + + private fun DiagnosticReporter.reportIncompatibleOverride( + declaration: FirDeclaration, + annotations: List, + notRefinedSupers: List>, + context: CheckerContext + ) { + val containingDeclarations = notRefinedSupers.mapNotNull { it.containingClass()?.toFirRegularClassSymbol(context.session) } + if (annotations.isEmpty()) { + reportOn(declaration.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) + } else { + for (annotation in annotations) { + reportOn(annotation.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) + } + } + } +} diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt index c7a58dd1744..b756d562e65 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/NativeDeclarationCheckers.kt @@ -5,8 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.native.checkers -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* object NativeDeclarationCheckers : DeclarationCheckers() { override val basicDeclarationCheckers: Set @@ -16,4 +15,19 @@ object NativeDeclarationCheckers : DeclarationCheckers() { FirNativeThreadLocalChecker, FirNativeIdentifierChecker ) -} \ No newline at end of file + + override val callableDeclarationCheckers: Set + get() = setOf( + FirNativeObjCRefinementChecker + ) + + override val classCheckers: Set + get() = setOf( + FirNativeObjCRefinementOverridesChecker + ) + + override val regularClassCheckers: Set + get() = setOf( + FirNativeObjCRefinementAnnotationChecker + ) +} diff --git a/compiler/testData/diagnostics/nativeTests/objCRefinement.kt b/compiler/testData/diagnostics/nativeTests/objCRefinement.kt index 2c4c0616647..270c150a62f 100644 --- a/compiler/testData/diagnostics/nativeTests/objCRefinement.kt +++ b/compiler/testData/diagnostics/nativeTests/objCRefinement.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: kotlin.kt package kotlin.native