[FE] Check annotations on actual class members including fake overrides

^KT-60668
^KT-60936
This commit is contained in:
Roman Efremov
2023-08-04 13:09:36 +02:00
committed by Space Team
parent d614f06259
commit ab1c0e3c48
30 changed files with 601 additions and 34 deletions
@@ -728,6 +728,18 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
}
@Test
@TestMetadata("classScopeInnerClasses.kt")
public void testClassScopeInnerClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/classScopeInnerClasses.kt");
}
@Test
@TestMetadata("classScopeViaTypealiasIncompatible.kt")
public void testClassScopeViaTypealiasIncompatible() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/classScopeViaTypealiasIncompatible.kt");
}
@Test
@TestMetadata("compatibleOverrides.kt")
public void testCompatibleOverrides() throws Exception {
@@ -794,6 +806,18 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt");
}
@Test
@TestMetadata("substitutionOverrideInTwoClasses.kt")
public void testSubstitutionOverrideInTwoClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/substitutionOverrideInTwoClasses.kt");
}
@Test
@TestMetadata("twoActualTypealiasesToSameClass.kt")
public void testTwoActualTypealiasesToSameClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/twoActualTypealiasesToSameClass.kt");
}
@Test
@TestMetadata("typealias.kt")
public void testTypealias() throws Exception {
@@ -728,6 +728,18 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
}
@Test
@TestMetadata("classScopeInnerClasses.kt")
public void testClassScopeInnerClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/classScopeInnerClasses.kt");
}
@Test
@TestMetadata("classScopeViaTypealiasIncompatible.kt")
public void testClassScopeViaTypealiasIncompatible() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/classScopeViaTypealiasIncompatible.kt");
}
@Test
@TestMetadata("compatibleOverrides.kt")
public void testCompatibleOverrides() throws Exception {
@@ -794,6 +806,18 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt");
}
@Test
@TestMetadata("substitutionOverrideInTwoClasses.kt")
public void testSubstitutionOverrideInTwoClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/substitutionOverrideInTwoClasses.kt");
}
@Test
@TestMetadata("twoActualTypealiasesToSameClass.kt")
public void testTwoActualTypealiasesToSameClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/twoActualTypealiasesToSameClass.kt");
}
@Test
@TestMetadata("typealias.kt")
public void testTypealias() throws Exception {
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
@@ -29,10 +28,7 @@ import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.getRetention
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -458,6 +459,21 @@ class FirExpectActualMatchingContextImpl private constructor(
private fun <K, V> Map<K, V>.asMutableMap(): MutableMap<K, V> = this as MutableMap
override val checkClassScopesForAnnotationCompatibility = true
override fun skipCheckingAnnotationsOfActualClassMember(actualMember: DeclarationSymbolMarker): Boolean {
return (actualMember.asSymbol().fir as? FirMemberDeclaration)?.isActual == true
}
override fun findPotentialExpectClassMembersForActual(
expectClass: RegularClassSymbolMarker,
actualClass: RegularClassSymbolMarker,
actualMember: DeclarationSymbolMarker,
): Map<FirBasedSymbol<*>, ExpectActualCompatibility<*>> {
val mapping = actualClass.asSymbol().fir.memberExpectForActual
return mapping?.get(actualMember to expectClass) ?: emptyMap()
}
object Factory : FirExpectActualMatchingContextFactory {
override fun create(
session: FirSession, scopeSession: ScopeSession,
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File
private val implicitlyActualizedAnnotationFqn = FqName("kotlin.jvm.ImplicitlyActualizedByJvmDeclaration")
@@ -40,7 +40,7 @@ internal class IrExpectActualAnnotationMatchingChecker(
if (expectSymbol is IrTypeParameterSymbol) {
continue
}
if (expectSymbol.isFakeOverride || actualSymbol.isFakeOverride) {
if (expectSymbol.isFakeOverride) {
continue
}
val incompatibility =
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualCollectionArgumentsCom
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.types.Variance
@@ -506,4 +507,15 @@ internal abstract class IrExpectActualMatchingContext(
val ir = asIr()
return ir.sourceElement() == null && ir.origin !is IrDeclarationOrigin.GeneratedByPlugin
}
// IR checker traverses member scope itself and collects mappings
override val checkClassScopesForAnnotationCompatibility = false
override fun skipCheckingAnnotationsOfActualClassMember(actualMember: DeclarationSymbolMarker): Boolean = error("Should not be called")
override fun findPotentialExpectClassMembersForActual(
expectClass: RegularClassSymbolMarker,
actualClass: RegularClassSymbolMarker,
actualMember: DeclarationSymbolMarker,
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>> = error("Should not be called")
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType as IncompatibilityType
object AbstractExpectActualAnnotationMatchChecker {
@@ -33,7 +34,9 @@ object AbstractExpectActualAnnotationMatchChecker {
expectSymbol: DeclarationSymbolMarker,
actualSymbol: DeclarationSymbolMarker,
context: ExpectActualMatchingContext<*>,
): Incompatibility? = with(context) { areAnnotationsCompatible(expectSymbol, actualSymbol) }
): Incompatibility? = with(context) {
areAnnotationsCompatible(expectSymbol, actualSymbol)
}
context (ExpectActualMatchingContext<*>)
private fun areAnnotationsCompatible(
@@ -70,9 +73,13 @@ object AbstractExpectActualAnnotationMatchChecker {
val expanded = actualSymbol.expandToRegularClass() ?: return null
return areClassAnnotationsCompatible(expectSymbol, expanded)
}
check(actualSymbol is RegularClassSymbolMarker)
commonForClassAndCallableChecks(expectSymbol, actualSymbol)?.let { return it }
// TODO(Roman.Efremov, KT-58551): fix actual typealias class members not checked in FE checkers
// TODO(Roman.Efremov, KT-58551): check annotations on fake overrides in case of implicit actualization
if (checkClassScopesForAnnotationCompatibility) {
checkAnnotationsInClassMemberScope(expectSymbol, actualSymbol)?.let { return it }
}
return null
}
@@ -137,4 +144,23 @@ object AbstractExpectActualAnnotationMatchChecker {
ExpectActualCollectionArgumentsCompatibilityCheckStrategy.Default
}
}
context (ExpectActualMatchingContext<*>)
private fun checkAnnotationsInClassMemberScope(
expectClass: RegularClassSymbolMarker,
actualClass: RegularClassSymbolMarker,
): Incompatibility? {
for (actualMember in actualClass.collectAllMembers(isActualDeclaration = true)) {
if (skipCheckingAnnotationsOfActualClassMember(actualMember)) {
continue
}
val expectToCompatibilityMap = findPotentialExpectClassMembersForActual(expectClass, actualClass, actualMember)
val expectMember = expectToCompatibilityMap.filter { it.value == ExpectActualCompatibility.Compatible }.keys.singleOrNull()
// Check also incompatible members if only one is found
?: expectToCompatibilityMap.keys.singleOrNull()
?: continue
areAnnotationsCompatible(expectMember, actualMember)?.let { return it }
}
return null
}
}
@@ -189,4 +189,26 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
val isRetentionSource: Boolean
val isOptIn: Boolean
}
val checkClassScopesForAnnotationCompatibility: Boolean
/**
* Determines whether it is needed to skip checking annotations on class member in [AbstractExpectActualAnnotationMatchChecker].
*
* This is needed to prevent checking member twice if it is real `actual` member (not fake override or member of
* class being typealiased).
* Example:
* ```
* actual class A {
* actual fun foo() {} // 1: checked itself, 2: checked as member of A
* }
* ```
*/
fun skipCheckingAnnotationsOfActualClassMember(actualMember: DeclarationSymbolMarker): Boolean
fun findPotentialExpectClassMembersForActual(
expectClass: RegularClassSymbolMarker,
actualClass: RegularClassSymbolMarker,
actualMember: DeclarationSymbolMarker,
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>>
}
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
import org.jetbrains.kotlin.resolve.checkers.OptInNames
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
@@ -387,4 +386,35 @@ class ClassicExpectActualMatchingContext(
this !is K1SyntheticClassifierSymbolMarker &&
!(this is CallableMemberDescriptor && kind == CallableMemberDescriptor.Kind.SYNTHESIZED)
}
override val checkClassScopesForAnnotationCompatibility = true
override fun skipCheckingAnnotationsOfActualClassMember(actualMember: DeclarationSymbolMarker): Boolean =
(actualMember as MemberDescriptor).isActual
override fun findPotentialExpectClassMembersForActual(
expectClass: RegularClassSymbolMarker,
actualClass: RegularClassSymbolMarker,
actualMember: DeclarationSymbolMarker,
): Map<MemberDescriptor, ExpectActualCompatibility<*>> {
val compatibilityToExpects = ExpectedActualResolver.findExpectForActualClassMember(
actualMember as MemberDescriptor,
actualClass as ClassDescriptor,
expectClass as ClassDescriptor,
this,
)
return buildMap {
for ((compatibility, expectMembers) in compatibilityToExpects.entries) {
for (expectMember in expectMembers) {
val oldValue = put(expectMember, compatibility)
if (oldValue != null) {
error(
"Several incompatibilities correspond to the same expect symbol: symbol=$expectMember, " +
"compatibilities=$oldValue, $compatibility"
)
}
}
}
}
}
}
@@ -54,6 +54,35 @@ object ExpectedActualResolver {
}
}
fun findExpectForActualClassMember(
actual: MemberDescriptor,
actualClass: ClassDescriptor,
expectClass: ClassDescriptor,
context: ClassicExpectActualMatchingContext,
): Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>> {
val candidates = with(context) {
expectClass.getMembersForExpectClass(actual.name)
}
return when (actual) {
is CallableMemberDescriptor -> {
matchActualCallableAgainstPotentialExpects(
actual,
candidates.filterIsInstance<CallableMemberDescriptor>(),
actualClass,
context
)
}
is ClassDescriptor -> {
matchActualClassAgainstPotentialExpects(
actual,
candidates.filterIsInstance<ClassifierDescriptorWithTypeParameters>(),
context
)
}
else -> emptyMap()
}
}
fun findExpectedForActual(
actual: MemberDescriptor,
moduleFilter: (ModuleDescriptor) -> Boolean = allModulesProvidingExpectsFor(actual.module),
@@ -1,11 +1,11 @@
// -- Module: <m1-common> --
// -- Module: <m1-jvm> --
/jvm.kt:27:14: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:29:14: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `class OnClass defined in root package in file common.kt` must be present with the same arguments on actual `class OnClass defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual class OnClass
^
/jvm.kt:30:16: warning: annotation `@Ann` is missing on actual declaration.
/jvm.kt:32:16: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `fun onMember(): Unit defined in OnMember` must be present with the same arguments on actual `fun onMember(): Unit defined in OnMember`, otherwise they might behave incorrectly.
actual fun onMember() {}
^
@@ -13,7 +13,11 @@ All annotations from expect `fun onMember(): Unit defined in OnMember` must be p
All annotations from expect `class ViaTypealias defined in root package in file common.kt` must be present with the same arguments on actual `class ViaTypealiasImpl defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual typealias ViaTypealias = ViaTypealiasImpl
^
/jvm.kt:40:12: warning: annotation `@WithArg(s = "str")` has different arguments on actual declaration: `@WithArg(s = "other str")`.
/jvm.kt:42:18: warning: annotation `@Ann` is missing on actual declaration.
All annotations from expect `fun foo(): Unit defined in MemberScopeViaTypealias` must be present with the same arguments on actual `fun foo(): Unit defined in MemberScopeViaTypealiasImpl`, otherwise they might behave incorrectly.
actual typealias MemberScopeViaTypealias = MemberScopeViaTypealiasImpl
^
/jvm.kt:45:12: warning: annotation `@WithArg(s = "str")` has different arguments on actual declaration: `@WithArg(s = "other str")`.
All annotations from expect `fun withDifferentArg(): Unit defined in root package in file common.kt` must be present with the same arguments on actual `fun withDifferentArg(): Unit defined in root package in file jvm.kt`, otherwise they might behave incorrectly.
actual fun withDifferentArg() {}
^
@@ -1,11 +1,14 @@
/jvm.kt:(86,93): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(88,95): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'class OnClass : Any' must be present with the same arguments on actual 'class OnClass : Any', otherwise they might behave incorrectly.
/jvm.kt:(134,142): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(136,144): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'fun onMember(): Unit' must be present with the same arguments on actual 'fun onMember(): Unit', otherwise they might behave incorrectly.
/jvm.kt:(213,225): warning: Annotation `@Ann()` is missing on actual declaration.
/jvm.kt:(194,206): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'class ViaTypealias : Any' must be present with the same arguments on actual 'class ViaTypealiasImpl : Any', otherwise they might behave incorrectly.
/jvm.kt:(279,295): warning: Annotation `@WithArg(s = String(str))` has different arguments on actual declaration: `@WithArg(s = String(other str))`.
/jvm.kt:(299,322): warning: Annotation `@Ann()` is missing on actual declaration.
All annotations from expect 'fun foo(): Unit' must be present with the same arguments on actual 'fun foo(): Unit', otherwise they might behave incorrectly.
/jvm.kt:(387,403): warning: Annotation `@WithArg(s = String(str))` has different arguments on actual declaration: `@WithArg(s = String(other str))`.
All annotations from expect 'fun withDifferentArg(): Unit' must be present with the same arguments on actual 'fun withDifferentArg(): Unit', otherwise they might behave incorrectly.
@@ -12,7 +12,9 @@ expect class OnMember {
}
@Ann
expect class ViaTypealias {
expect class ViaTypealias
expect class MemberScopeViaTypealias {
@Ann
fun foo()
}
@@ -30,11 +32,14 @@ actual class OnMember {
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onMember<!>() {}<!>
}
class ViaTypealiasImpl {
class ViaTypealiasImpl
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ViaTypealias<!> = ViaTypealiasImpl<!>
class MemberScopeViaTypealiasImpl {
fun foo() {}
}
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ViaTypealias<!> = ViaTypealiasImpl<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MemberScopeViaTypealias<!> = MemberScopeViaTypealiasImpl<!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>@WithArg("other str")
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>withDifferentArg<!>() {}<!>
@@ -12,7 +12,9 @@ expect class OnMember {
}
@Ann
expect class ViaTypealias {
expect class ViaTypealias
expect class MemberScopeViaTypealias {
@Ann
fun foo()
}
@@ -30,11 +32,14 @@ actual class OnMember {
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onMember<!>() {}
}
class ViaTypealiasImpl {
fun foo() {}
}
class ViaTypealiasImpl
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ViaTypealias<!> = ViaTypealiasImpl
class MemberScopeViaTypealiasImpl {
fun foo() {}
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MemberScopeViaTypealias<!> = MemberScopeViaTypealiasImpl
@WithArg("other str")
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>withDifferentArg<!>() {}
@@ -0,0 +1,22 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect class A {
class B {
class C {
@Ann
fun foo()
}
}
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
actual class A {
actual class B {
actual class C {
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>foo<!>() {}<!>
}
}
}
@@ -0,0 +1,22 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect class A {
class B {
class C {
@Ann
fun foo()
}
}
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
actual class A {
actual class B {
actual class C {
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>foo<!>() {}
}
}
}
@@ -0,0 +1,27 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
<!INCOMPATIBLE_MATCHING{JVM}!>expect class WeakIncompatibility {
<!INCOMPATIBLE_MATCHING{JVM}!>@Ann
fun foo(p: String)<!>
}<!>
<!INCOMPATIBLE_MATCHING{JVM}!>expect class StrongIncompatibility {
<!INCOMPATIBLE_MATCHING{JVM}!>@Ann
fun foo(p: Int)<!>
}<!>
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
class WeakIncompatibilityImpl {
fun foo(differentName: String) {}
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>WeakIncompatibility<!> = WeakIncompatibilityImpl
class StrongIncompatibilityImpl {
fun foo(p: String) {} // Different param type
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>StrongIncompatibility<!> = StrongIncompatibilityImpl
@@ -0,0 +1,27 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect class WeakIncompatibility {
@Ann
fun foo(p: String)
}
expect class StrongIncompatibility {
@Ann
fun foo(p: Int)
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
class WeakIncompatibilityImpl {
fun foo(differentName: String) {}
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>WeakIncompatibility<!> = WeakIncompatibilityImpl
class StrongIncompatibilityImpl {
fun foo(p: String) {} // Different param type
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>StrongIncompatibility<!> = StrongIncompatibilityImpl
@@ -0,0 +1,31 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
abstract class A {
@Ann
open fun noAnnotationOnActual() {}
}
expect class FakeOverrideExpect : A
interface I {
fun noAnnotationOnActual()
}
expect class FakeOverrideActual : I {
@Ann
override fun noAnnotationOnActual()
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
actual class FakeOverrideExpect : A() {
override fun noAnnotationOnActual() {}
}
abstract class Intermediate : I {
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>override fun noAnnotationOnActual() {}<!>
}
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>FakeOverrideActual<!> : Intermediate(), I
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
@@ -29,4 +28,4 @@ abstract class Intermediate : I {
override fun noAnnotationOnActual() {}
}
actual class FakeOverrideActual : Intermediate(), I
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>FakeOverrideActual<!> : Intermediate(), I
@@ -0,0 +1,24 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect class WithAnn {
@Ann
fun foo(p: String)
}
expect class WithoutAnn {
fun foo(p: String)
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
abstract class Parent<T> {
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>open fun foo(p: T) {}<!>
}
abstract class Intermediate : Parent<String>()
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>WithAnn<!> : Intermediate()
actual class WithoutAnn : Intermediate()
@@ -0,0 +1,24 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect class WithAnn {
@Ann
fun foo(p: String)
}
expect class WithoutAnn {
fun foo(p: String)
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
abstract class Parent<T> {
open fun foo(p: T) {}
}
abstract class Intermediate : Parent<String>()
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>WithAnn<!> : Intermediate()
actual class WithoutAnn : Intermediate()
@@ -0,0 +1,21 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect class WithAnn {
@Ann
fun foo()
}
expect class WithoutAnn {
fun foo()
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
class Impl {
fun foo() {}
}
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>WithAnn<!> = Impl<!>
actual typealias WithoutAnn = Impl
@@ -0,0 +1,21 @@
// MODULE: m1-common
// FILE: common.kt
annotation class Ann
expect class WithAnn {
@Ann
fun foo()
}
expect class WithoutAnn {
fun foo()
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
class Impl {
fun foo() {}
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>WithAnn<!> = Impl
actual typealias WithoutAnn = Impl
@@ -1,7 +1,15 @@
// WITH_STDLIB
// MODULE: m1-common
// FILE: common.kt
@Target(AnnotationTarget.TYPEALIAS, AnnotationTarget.CLASS)
@Target(
AnnotationTarget.TYPEALIAS,
AnnotationTarget.CLASS,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.CONSTRUCTOR,
)
annotation class Ann
@Ann
@@ -10,6 +18,32 @@ expect class KtTypealiasNotMatch
@Ann
expect class AnnotationsNotConsideredOnTypealias
annotation class ComplexAnn(val s: String)
expect class MethodsInsideTypealias {
@Ann
fun foo()
}
expect class ValueInsideTypealias {
@Ann
val value: String
}
expect class ConstructorInsideTypealias @Ann constructor()
expect class MethodWithComplexAnnInsideTypealias {
@ComplexAnn("1" + "2")
fun withComplexAnn()
}
expect class InnerClassInsideTypealias {
class Foo {
@Ann
fun foo()
}
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
class KtTypealiasNotMatchImpl
@@ -20,3 +54,34 @@ class AnnotationsNotConsideredOnTypealiasImpl
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>@Ann
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>AnnotationsNotConsideredOnTypealias<!> = AnnotationsNotConsideredOnTypealiasImpl<!>
class MethodsInsideTypealiasImpl {
fun foo() {}
}
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MethodsInsideTypealias<!> = MethodsInsideTypealiasImpl<!>
class ValueInsideTypealiasImpl {
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>val value: String = ""<!>
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ValueInsideTypealias<!> = ValueInsideTypealiasImpl
class ConstructorInsideTypealiasImpl
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ConstructorInsideTypealias<!> = ConstructorInsideTypealiasImpl<!>
class MethodWithComplexAnnInsideTypealiasImpl {
@ComplexAnn("13")
fun withComplexAnn() {}
}
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias MethodWithComplexAnnInsideTypealias = MethodWithComplexAnnInsideTypealiasImpl<!>
class InnerClassInsideTypealiasImpl {
class Foo {
fun foo() {}
}
}
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>InnerClassInsideTypealias<!> = InnerClassInsideTypealiasImpl<!>
@@ -1,7 +1,15 @@
// WITH_STDLIB
// MODULE: m1-common
// FILE: common.kt
@Target(AnnotationTarget.TYPEALIAS, AnnotationTarget.CLASS)
@Target(
AnnotationTarget.TYPEALIAS,
AnnotationTarget.CLASS,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.CONSTRUCTOR,
)
annotation class Ann
@Ann
@@ -10,6 +18,32 @@ expect class KtTypealiasNotMatch
@Ann
expect class AnnotationsNotConsideredOnTypealias
annotation class ComplexAnn(val s: String)
expect class MethodsInsideTypealias {
@Ann
fun foo()
}
expect class ValueInsideTypealias {
@Ann
val value: String
}
expect class ConstructorInsideTypealias @Ann constructor()
expect class MethodWithComplexAnnInsideTypealias {
@ComplexAnn("1" + "2")
fun withComplexAnn()
}
expect class InnerClassInsideTypealias {
class Foo {
@Ann
fun foo()
}
}
// MODULE: m1-jvm()()(m1-common)
// FILE: jvm.kt
class KtTypealiasNotMatchImpl
@@ -20,3 +54,34 @@ class AnnotationsNotConsideredOnTypealiasImpl
@Ann
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>AnnotationsNotConsideredOnTypealias<!> = AnnotationsNotConsideredOnTypealiasImpl
class MethodsInsideTypealiasImpl {
fun foo() {}
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MethodsInsideTypealias<!> = MethodsInsideTypealiasImpl
class ValueInsideTypealiasImpl {
val value: String = ""
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ValueInsideTypealias<!> = ValueInsideTypealiasImpl
class ConstructorInsideTypealiasImpl
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ConstructorInsideTypealias<!> = ConstructorInsideTypealiasImpl
class MethodWithComplexAnnInsideTypealiasImpl {
@ComplexAnn("13")
fun withComplexAnn() {}
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MethodWithComplexAnnInsideTypealias<!> = MethodWithComplexAnnInsideTypealiasImpl
class InnerClassInsideTypealiasImpl {
class Foo {
fun foo() {}
}
}
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>InnerClassInsideTypealias<!> = InnerClassInsideTypealiasImpl
@@ -1,5 +1,5 @@
// WITH_STDLIB
// DIAGNOSTICS: -ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION
// DIAGNOSTICS: -ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION, -ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NON_FINAL_EXPECT_CLASSIFIER, -ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_SUPERTYPES_AS_NON_FINAL_EXPECT_CLASSIFIER
// MODULE: m1-common
// FILE: common.kt
@Target(
@@ -40,4 +40,4 @@ expect abstract class MyAbstractIterator<T> {
actual typealias MyDeprecatedMatch = kotlin.Deprecated
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias MyAbstractIterator<T> = AbstractIterator<T><!>
<!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MyAbstractIterator<!><T> = AbstractIterator<T><!>
@@ -1,5 +1,5 @@
// WITH_STDLIB
// DIAGNOSTICS: -ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION
// DIAGNOSTICS: -ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION, -ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NON_FINAL_EXPECT_CLASSIFIER, -ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_SUPERTYPES_AS_NON_FINAL_EXPECT_CLASSIFIER
// MODULE: m1-common
// FILE: common.kt
@Target(
@@ -40,4 +40,4 @@ actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MyDeprecatedNotMatch<!>
actual typealias MyDeprecatedMatch = kotlin.Deprecated
actual typealias <!ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NON_FINAL_EXPECT_CLASSIFIER, ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_SUPERTYPES_AS_NON_FINAL_EXPECT_CLASSIFIER!>MyAbstractIterator<!><T> = AbstractIterator<T>
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MyAbstractIterator<!><T> = AbstractIterator<T>
@@ -23497,6 +23497,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
}
@Test
@TestMetadata("classScopeInnerClasses.kt")
public void testClassScopeInnerClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/classScopeInnerClasses.kt");
}
@Test
@TestMetadata("classScopeViaTypealiasIncompatible.kt")
public void testClassScopeViaTypealiasIncompatible() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/classScopeViaTypealiasIncompatible.kt");
}
@Test
@TestMetadata("compatibleOverrides.kt")
public void testCompatibleOverrides() throws Exception {
@@ -23563,6 +23575,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/sourceRetentionAnnotationsWhenTypealias.kt");
}
@Test
@TestMetadata("substitutionOverrideInTwoClasses.kt")
public void testSubstitutionOverrideInTwoClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/substitutionOverrideInTwoClasses.kt");
}
@Test
@TestMetadata("twoActualTypealiasesToSameClass.kt")
public void testTwoActualTypealiasesToSameClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/twoActualTypealiasesToSameClass.kt");
}
@Test
@TestMetadata("typealias.kt")
public void testTypealias() throws Exception {