[FE] Implement FE logic of expect actual annotations matching
This implementation only checks annotations set on expect/actual declarations and requires further refinement (e.g. checking of other annotation targets, class scopes within typealiases). ^KT-58551
This commit is contained in:
committed by
Space Team
parent
b1bdb619d8
commit
1a4ab9bb4b
+8
@@ -3504,6 +3504,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT) { firDiagnostic ->
|
||||
ActualAnnotationsNotMatchExpectImpl(
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.b),
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION) { firDiagnostic ->
|
||||
InitializerRequiredForDestructuringDeclarationImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
|
||||
+6
@@ -2448,6 +2448,12 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
val typealiasedClassId: ClassId
|
||||
}
|
||||
|
||||
interface ActualAnnotationsNotMatchExpect : KtFirDiagnostic<KtElement> {
|
||||
override val diagnosticClass get() = ActualAnnotationsNotMatchExpect::class
|
||||
val expect: KtSymbol
|
||||
val actual: KtSymbol
|
||||
}
|
||||
|
||||
interface InitializerRequiredForDestructuringDeclaration : KtFirDiagnostic<KtDestructuringDeclaration> {
|
||||
override val diagnosticClass get() = InitializerRequiredForDestructuringDeclaration::class
|
||||
}
|
||||
|
||||
+7
@@ -2952,6 +2952,13 @@ internal class ActualTypealiasToSpecialAnnotationImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<KtTypeAlias>(firDiagnostic, token), KtFirDiagnostic.ActualTypealiasToSpecialAnnotation
|
||||
|
||||
internal class ActualAnnotationsNotMatchExpectImpl(
|
||||
override val expect: KtSymbol,
|
||||
override val actual: KtSymbol,
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.ActualAnnotationsNotMatchExpect
|
||||
|
||||
internal class InitializerRequiredForDestructuringDeclarationImpl(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
|
||||
+94
@@ -205,6 +205,100 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class AnnotationMatching {
|
||||
@Test
|
||||
public void testAllFilesPresentInAnnotationMatching() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsConstExpressions.kt")
|
||||
public void testAnnotationArgumentsConstExpressions() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsDefaults.kt")
|
||||
public void testAnnotationArgumentsDefaults() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationTypeParameters.kt")
|
||||
public void testAnnotationTypeParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicOnDeclaration.kt")
|
||||
public void testBasicOnDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("checkDiagnosticFullText.kt")
|
||||
public void testCheckDiagnosticFullText() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compatibleOverrides.kt")
|
||||
public void testCompatibleOverrides() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentOrder.kt")
|
||||
public void testDifferentOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("floatNumbersComparison.kt")
|
||||
public void testFloatNumbersComparison() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kclassArgWithExpectClass.kt")
|
||||
public void testKclassArgWithExpectClass() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnaloguesForJavaAnnotations.kt")
|
||||
public void testKotlinAnaloguesForJavaAnnotations() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealias.kt")
|
||||
public void testTypealias() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToJavaLibrary.kt")
|
||||
public void testTypealiasToJavaLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToKtLibrary.kt")
|
||||
public void testTypealiasToKtLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withOtherIncomatibilities.kt")
|
||||
public void testWithOtherIncomatibilities() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+94
@@ -205,6 +205,100 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class AnnotationMatching {
|
||||
@Test
|
||||
public void testAllFilesPresentInAnnotationMatching() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsConstExpressions.kt")
|
||||
public void testAnnotationArgumentsConstExpressions() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsDefaults.kt")
|
||||
public void testAnnotationArgumentsDefaults() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationTypeParameters.kt")
|
||||
public void testAnnotationTypeParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicOnDeclaration.kt")
|
||||
public void testBasicOnDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("checkDiagnosticFullText.kt")
|
||||
public void testCheckDiagnosticFullText() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compatibleOverrides.kt")
|
||||
public void testCompatibleOverrides() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentOrder.kt")
|
||||
public void testDifferentOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("floatNumbersComparison.kt")
|
||||
public void testFloatNumbersComparison() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kclassArgWithExpectClass.kt")
|
||||
public void testKclassArgWithExpectClass() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnaloguesForJavaAnnotations.kt")
|
||||
public void testKotlinAnaloguesForJavaAnnotations() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealias.kt")
|
||||
public void testTypealias() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToJavaLibrary.kt")
|
||||
public void testTypealiasToJavaLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToKtLibrary.kt")
|
||||
public void testTypealiasToKtLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withOtherIncomatibilities.kt")
|
||||
public void testWithOtherIncomatibilities() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+5
@@ -1180,6 +1180,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error<KtTypeAlias>(PositioningStrategy.TYPEALIAS_TYPE_REFERENCE) {
|
||||
parameter<ClassId>("typealiasedClassId")
|
||||
}
|
||||
|
||||
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning<KtElement>(PositioningStrategy.DECLARATION_NAME_ONLY) {
|
||||
parameter<Symbol>("expect")
|
||||
parameter<Symbol>("actual")
|
||||
}
|
||||
}
|
||||
|
||||
val DESTRUCTING_DECLARATION by object : DiagnosticGroup("Destructuring declaration") {
|
||||
|
||||
@@ -628,6 +628,7 @@ object FirErrors {
|
||||
val NOT_A_MULTIPLATFORM_COMPILATION by error0<PsiElement>()
|
||||
val EXPECT_ACTUAL_OPT_IN_ANNOTATION by error0<KtNamedDeclaration>(SourceElementPositioningStrategies.EXPECT_ACTUAL_MODIFIER)
|
||||
val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error1<KtTypeAlias, ClassId>(SourceElementPositioningStrategies.TYPEALIAS_TYPE_REFERENCE)
|
||||
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME_ONLY)
|
||||
|
||||
// Destructuring declaration
|
||||
val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0<KtDestructuringDeclaration>()
|
||||
|
||||
+27
-4
@@ -20,17 +20,20 @@ import org.jetbrains.kotlin.fir.declarations.utils.isActual
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExternal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isTailRec
|
||||
import org.jetbrains.kotlin.fir.expectActualMatchingContextFactory
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.scopes.collectAllFunctions
|
||||
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.*
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.toSymbol
|
||||
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.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.*
|
||||
@@ -176,7 +179,9 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
|
||||
else -> {}
|
||||
}
|
||||
val expectedSingleCandidate = symbol.getSingleExpectForActualOrNull()
|
||||
// We want to report errors even if a candidate is incompatible, but it's single
|
||||
val expectedSingleCandidate = compatibilityToMembersMap[Compatible]?.singleOrNull()
|
||||
?: symbol.getSingleExpectForActualOrNull()
|
||||
if (expectedSingleCandidate != null) {
|
||||
checkIfExpectHasDefaultArgumentsAndActualizedWithTypealias(
|
||||
expectedSingleCandidate,
|
||||
@@ -185,6 +190,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
reporter,
|
||||
)
|
||||
checkOptInAnnotation(declaration, expectedSingleCandidate, context, reporter)
|
||||
checkAnnotationsMatch(expectedSingleCandidate, symbol, context, reporter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +249,23 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkAnnotationsMatch(
|
||||
expectSymbol: FirBasedSymbol<*>,
|
||||
actualSymbol: FirBasedSymbol<*>,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
val matchingContext = context.session.expectActualMatchingContextFactory.create(context.session, context.scopeSession)
|
||||
val incompatibility =
|
||||
AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectSymbol, actualSymbol, matchingContext) ?: return
|
||||
reporter.reportOn(
|
||||
actualSymbol.source, FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
||||
incompatibility.expectSymbol as FirBasedSymbol<*>,
|
||||
incompatibility.actualSymbol as FirBasedSymbol<*>,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
fun Map<out ExpectActualCompatibility<*>, *>.allStrongIncompatibilities(): Boolean {
|
||||
return keys.all { it is Incompatible && it.kind == IncompatibilityKind.STRONG }
|
||||
}
|
||||
|
||||
+10
@@ -178,4 +178,14 @@ object FirDiagnosticRenderers {
|
||||
}
|
||||
|
||||
val FUNCTIONAL_TYPE_KINDS = KtDiagnosticRenderers.COLLECTION(FUNCTIONAL_TYPE_KIND)
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
val SYMBOL_WITH_ANNOTATIONS = Renderer { s: FirBasedSymbol<*> ->
|
||||
FirRenderer(
|
||||
typeRenderer = ConeTypeRenderer(),
|
||||
idRenderer = ConeIdShortRenderer(),
|
||||
classMemberRenderer = null,
|
||||
bodyRenderer = null,
|
||||
).renderElementAsString(s.fir, trim = true)
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING
|
||||
@@ -1854,6 +1855,13 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.",
|
||||
TO_STRING
|
||||
)
|
||||
map.put(
|
||||
ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
||||
"All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.\n" +
|
||||
"Expected: {0}\n" +
|
||||
"Actual: {1}",
|
||||
FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS, FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS
|
||||
)
|
||||
|
||||
// Destructuring declaration
|
||||
map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration")
|
||||
|
||||
+48
-4
@@ -11,12 +11,13 @@ import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext
|
||||
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContextFactory
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.collectEnumEntries
|
||||
import org.jetbrains.kotlin.fir.declarations.isAnnotationConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.coneType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.mpp.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -311,6 +313,48 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
override val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
get() = asSymbol().rawStatus.hasStableParameterNames
|
||||
|
||||
override val DeclarationSymbolMarker.annotations: List<AnnotationCallInfo>
|
||||
get() = asSymbol().resolvedAnnotationsWithArguments.map(::AnnotationCallInfoImpl)
|
||||
|
||||
override fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean {
|
||||
fun AnnotationCallInfo.getFirAnnotation(): FirAnnotation {
|
||||
return (this as AnnotationCallInfoImpl).annotation
|
||||
}
|
||||
return areFirAnnotationsEqual(annotation1.getFirAnnotation(), annotation2.getFirAnnotation())
|
||||
}
|
||||
|
||||
private fun areFirAnnotationsEqual(annotation1: FirAnnotation, annotation2: FirAnnotation): Boolean {
|
||||
if (!areCompatibleExpectActualTypes(annotation1.typeRef.coneType, annotation2.typeRef.coneType)) {
|
||||
return false
|
||||
}
|
||||
val args1 = annotation1.argumentMapping.mapping
|
||||
val args2 = annotation2.argumentMapping.mapping
|
||||
if (args1.size != args2.size) {
|
||||
return false
|
||||
}
|
||||
return args1.all { (key, value1) ->
|
||||
val value2 = args2[key]
|
||||
value2 != null && areAnnotationArgumentsEqual(value1, value2)
|
||||
}
|
||||
}
|
||||
|
||||
private fun areAnnotationArgumentsEqual(expression1: FirExpression, expression2: FirExpression): Boolean {
|
||||
// In K2 const expression calculated in backend.
|
||||
// Because of that, we have "honest" checker at backend IR stage
|
||||
// and "only simplest case" checker in frontend, so that we have at least some reporting in the IDE.
|
||||
return when {
|
||||
expression1 is FirConstExpression<*> && expression2 is FirConstExpression<*> -> {
|
||||
expression1.value == expression2.value
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AnnotationCallInfoImpl(val annotation: FirAnnotation) : AnnotationCallInfo {
|
||||
override val classId: ClassId?
|
||||
get() = annotation.toAnnotationClassId(actualSession)
|
||||
}
|
||||
|
||||
object Factory : FirExpectActualMatchingContextFactory {
|
||||
override fun create(session: FirSession, scopeSession: ScopeSession): FirExpectActualMatchingContextImpl =
|
||||
FirExpectActualMatchingContextImpl(session, scopeSession)
|
||||
|
||||
@@ -840,6 +840,8 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtNamedDeclaration> EXPECT_ACTUAL_OPT_IN_ANNOTATION = DiagnosticFactory0.create(ERROR, EXPECT_ACTUAL_MODIFIER);
|
||||
DiagnosticFactory1<KtTypeAlias, ClassId> ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION =
|
||||
DiagnosticFactory1.create(ERROR, TYPEALIAS_TYPE_REFERENCE);
|
||||
DiagnosticFactory2<KtNamedDeclaration, DeclarationDescriptor, DeclarationDescriptor> ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT
|
||||
= DiagnosticFactory2.create(WARNING, DECLARATION_NAME_ONLY);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
+5
@@ -396,6 +396,11 @@ public class DefaultErrorMessages {
|
||||
MAP.put(ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION,
|
||||
"`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.",
|
||||
TO_STRING);
|
||||
MAP.put(ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
||||
"All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.\n" +
|
||||
" Expected: {0}\n" +
|
||||
" Actual: {1}",
|
||||
DESCRIPTOR_WITH_ANNOTATIONS, DESCRIPTOR_WITH_ANNOTATIONS);
|
||||
|
||||
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
|
||||
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
|
||||
|
||||
@@ -32,8 +32,10 @@ import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.isCommon
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.DEBUG_TEXT
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
|
||||
import org.jetbrains.kotlin.renderer.PropertyAccessorRenderingPolicy
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.*
|
||||
@@ -708,6 +710,14 @@ object Renderers {
|
||||
val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
|
||||
@JvmField
|
||||
val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
|
||||
|
||||
@JvmField
|
||||
val DESCRIPTOR_WITH_ANNOTATIONS = DescriptorRenderer.withOptions {
|
||||
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
|
||||
modifiers = modifiers.plus(DescriptorRendererModifier.ANNOTATIONS)
|
||||
withDefinedIn = true
|
||||
}.asRenderer()
|
||||
|
||||
@JvmField
|
||||
val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
|
||||
withoutTypeParameters = false
|
||||
|
||||
+22
-1
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isPrimaryConstructorOfInlineClass
|
||||
@@ -338,9 +339,11 @@ class ExpectedActualDeclarationChecker(
|
||||
checkOptInAnnotation(reportOn, descriptor, expected, trace)
|
||||
}
|
||||
}
|
||||
val expectSingleCandidate = compatibility.values.singleOrNull()?.singleOrNull()
|
||||
// We want to report errors even if a candidate is incompatible, but it's single
|
||||
val expectSingleCandidate = (compatibility[Compatible] ?: compatibility.values.singleOrNull())?.singleOrNull()
|
||||
if (expectSingleCandidate != null) {
|
||||
checkIfExpectHasDefaultArgumentsAndActualizedWithTypealias(expectSingleCandidate, reportOn, trace)
|
||||
checkAnnotationsMatch(expectSingleCandidate, descriptor, reportOn, trace)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,6 +446,24 @@ class ExpectedActualDeclarationChecker(
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAnnotationsMatch(
|
||||
expectDescriptor: MemberDescriptor,
|
||||
actualDescriptor: MemberDescriptor,
|
||||
reportOn: KtNamedDeclaration,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
val context = ClassicExpectActualMatchingContext(actualDescriptor.module)
|
||||
val incompatibility =
|
||||
AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectDescriptor, actualDescriptor, context) ?: return
|
||||
trace.report(
|
||||
Errors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT.on(
|
||||
reportOn,
|
||||
incompatibility.expectSymbol as DeclarationDescriptor,
|
||||
incompatibility.actualSymbol as DeclarationDescriptor
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun Map<out ExpectActualCompatibility<MemberDescriptor>, Collection<MemberDescriptor>>.allStrongIncompatibilities(): Boolean =
|
||||
this.keys.all { it is Incompatible && it.kind == IncompatibilityKind.STRONG }
|
||||
|
||||
+15
-1
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
@@ -25,7 +26,10 @@ import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.types.model.AnnotationMarker
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSystemContext
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.castAll
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
||||
@@ -75,6 +79,7 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
private fun TypeParameterSymbolMarker.asIr(): IrTypeParameter = (this as IrTypeParameterSymbol).owner
|
||||
private fun RegularClassSymbolMarker.asIr(): IrClass = (this as IrClassSymbol).owner
|
||||
private fun TypeAliasSymbolMarker.asIr(): IrTypeAlias = (this as IrTypeAliasSymbol).owner
|
||||
private fun AnnotationMarker.asIr(): IrConstructorCall = this as IrConstructorCall
|
||||
|
||||
private inline fun <reified T : IrDeclaration> DeclarationSymbolMarker.safeAsIr(): T? = (this as IrSymbol).owner as? T
|
||||
|
||||
@@ -440,4 +445,13 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
|
||||
abstract fun onMatchedClasses(expectClassSymbol: IrClassSymbol, actualClassSymbol: IrClassSymbol)
|
||||
abstract fun onMatchedCallables(expectSymbol: IrSymbol, actualSymbol: IrSymbol)
|
||||
|
||||
override val DeclarationSymbolMarker.annotations: List<ExpectActualMatchingContext.AnnotationCallInfo>
|
||||
// TODO(Roman.Efremov): implement in subsequent commits
|
||||
get() = emptyList()
|
||||
|
||||
override fun areAnnotationArgumentsEqual(annotation1: ExpectActualMatchingContext.AnnotationCallInfo, annotation2: ExpectActualMatchingContext.AnnotationCallInfo): Boolean {
|
||||
// TODO(Roman.Efremov): implement in subsequent commits
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.calls.mpp
|
||||
|
||||
import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker
|
||||
import org.jetbrains.kotlin.mpp.TypeAliasSymbolMarker
|
||||
|
||||
object AbstractExpectActualAnnotationMatchChecker {
|
||||
class Incompatibility(val expectSymbol: DeclarationSymbolMarker, val actualSymbol: DeclarationSymbolMarker)
|
||||
|
||||
fun areAnnotationsCompatible(
|
||||
expectSymbol: DeclarationSymbolMarker,
|
||||
actualSymbol: DeclarationSymbolMarker,
|
||||
context: ExpectActualMatchingContext<*>,
|
||||
): Incompatibility? = with(context) { areAnnotationsCompatible(expectSymbol, actualSymbol) }
|
||||
|
||||
context (ExpectActualMatchingContext<*>)
|
||||
private fun areAnnotationsCompatible(
|
||||
expectSymbol: DeclarationSymbolMarker,
|
||||
actualSymbol: DeclarationSymbolMarker,
|
||||
): Incompatibility? {
|
||||
if (actualSymbol is TypeAliasSymbolMarker) {
|
||||
val expanded = actualSymbol.expandToRegularClass() ?: return null
|
||||
return areAnnotationsCompatible(expectSymbol, expanded)
|
||||
}
|
||||
|
||||
val actualAnnotationsByName = actualSymbol.annotations.groupBy { it.classId }
|
||||
|
||||
for (expectAnnotation in expectSymbol.annotations) {
|
||||
val actualAnnotationsWithSameClassId = actualAnnotationsByName[expectAnnotation.classId] ?: emptyList()
|
||||
if (actualAnnotationsWithSameClassId.none { areAnnotationArgumentsEqual(expectAnnotation, it) }) {
|
||||
return Incompatibility(expectSymbol, actualSymbol)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
+9
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.mpp.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -157,4 +158,12 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
||||
expectSymbol: DeclarationSymbolMarker,
|
||||
actualSymbolsByIncompatibility: Map<ExpectActualCompatibility.Incompatible<*>, List<DeclarationSymbolMarker>>
|
||||
) {}
|
||||
|
||||
val DeclarationSymbolMarker.annotations: List<AnnotationCallInfo>
|
||||
|
||||
fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean
|
||||
|
||||
interface AnnotationCallInfo {
|
||||
val classId: ClassId?
|
||||
}
|
||||
}
|
||||
|
||||
+21
-3
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.resolve.multiplatform
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.mpp.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
@@ -14,9 +15,8 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getKotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
@@ -35,6 +35,7 @@ class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) :
|
||||
override val shouldCheckReturnTypesOfCallables: Boolean
|
||||
get() = true
|
||||
|
||||
private fun DeclarationSymbolMarker.asDescriptor(): DeclarationDescriptor = this as DeclarationDescriptor
|
||||
private fun CallableSymbolMarker.asDescriptor(): CallableDescriptor = this as CallableDescriptor
|
||||
private fun FunctionSymbolMarker.asDescriptor(): FunctionDescriptor = this as FunctionDescriptor
|
||||
private fun PropertySymbolMarker.asDescriptor(): PropertyDescriptor = this as PropertyDescriptor
|
||||
@@ -328,4 +329,21 @@ class ClassicExpectActualMatchingContext(val platformModule: ModuleDescriptor) :
|
||||
|
||||
override val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
get() = asDescriptor().hasStableParameterNames()
|
||||
|
||||
override val DeclarationSymbolMarker.annotations: List<AnnotationCallInfo>
|
||||
get() = asDescriptor().annotations.map(::AnnotationCallInfoImpl)
|
||||
|
||||
|
||||
override fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean {
|
||||
fun AnnotationCallInfo.getDescriptor(): AnnotationDescriptor = (this as AnnotationCallInfoImpl).annotationDescriptor
|
||||
|
||||
return areExpressionConstValuesEqual(annotation1.getDescriptor(), annotation2.getDescriptor())
|
||||
}
|
||||
|
||||
private class AnnotationCallInfoImpl(
|
||||
val annotationDescriptor: AnnotationDescriptor,
|
||||
) : AnnotationCallInfo {
|
||||
override val classId: ClassId?
|
||||
get() = annotationDescriptor.annotationClass?.classId
|
||||
}
|
||||
}
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.multiplatform
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
|
||||
internal fun ExpectActualMatchingContext<*>.areExpressionConstValuesEqual(a: Any?, b: Any?): Boolean {
|
||||
return when {
|
||||
a is AnnotationDescriptor && b is AnnotationDescriptor -> {
|
||||
val aArgs = a.allValueArguments
|
||||
val bArgs = b.allValueArguments
|
||||
a.fqName == b.fqName &&
|
||||
aArgs.size == bArgs.size &&
|
||||
areCompatibleExpectActualTypes(a.type, b.type) &&
|
||||
aArgs.keys.all { k -> areExpressionConstValuesEqual(aArgs[k], bArgs[k]) }
|
||||
}
|
||||
a is ConstantValue<*> && b is ConstantValue<*> -> {
|
||||
areExpressionConstValuesEqual(a.value, b.value)
|
||||
}
|
||||
a is Collection<*> && b is Collection<*> -> {
|
||||
a.size == b.size && a.zip(b).all { (f, s) -> areExpressionConstValuesEqual(f, s) }
|
||||
}
|
||||
a is Array<*> && b is Array<*> -> {
|
||||
a.size == b.size && a.zip(b).all { (f, s) -> areExpressionConstValuesEqual(f, s) }
|
||||
}
|
||||
else -> a == b
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
annotation class ClassArgAnn(val clazz: KClass<*>)
|
||||
|
||||
class ClassForReference {
|
||||
class ClassForReference
|
||||
}
|
||||
|
||||
@ClassArgAnn(ClassForReference::class)
|
||||
expect fun getClassExpression()
|
||||
|
||||
@ClassArgAnn(ClassForReference.ClassForReference::class)
|
||||
expect fun differentClassesWithSameName()
|
||||
|
||||
annotation class StringArgAnn(val s: String)
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
expect fun stringConstant()
|
||||
|
||||
@StringArgAnn("1" + ".9")
|
||||
expect fun stringConcatentation()
|
||||
|
||||
object Constants {
|
||||
const val STR = "1"
|
||||
}
|
||||
|
||||
@StringArgAnn(Constants.STR)
|
||||
expect fun constantFromInsideObject()
|
||||
|
||||
@StringArgAnn(Constants.STR + ".9")
|
||||
expect fun stringConcatentationWithProperty()
|
||||
|
||||
enum class MyEnum { FOO, BAR }
|
||||
|
||||
annotation class EnumArgAnn(val e: MyEnum)
|
||||
|
||||
@EnumArgAnn(MyEnum.FOO)
|
||||
expect fun enumArg()
|
||||
|
||||
annotation class VarargAnn(vararg val strings: String)
|
||||
|
||||
@VarargAnn("foo", "bar")
|
||||
expect fun varargInAnnotation()
|
||||
|
||||
@VarargAnn(*["foo", "bar"])
|
||||
expect fun varargInAnnotationWithArraySpread()
|
||||
|
||||
annotation class ArrayArgAnn(val strings: Array<String>)
|
||||
|
||||
@ArrayArgAnn(["foo", "bar"])
|
||||
expect fun arrayInAnnotation()
|
||||
|
||||
@ArrayArgAnn(["foo", "bar"])
|
||||
expect fun arrayInAnnotationNotMatch()
|
||||
|
||||
annotation class NestedAnnArg(val text: String, vararg val children: NestedAnnArg)
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("2.2")
|
||||
)
|
||||
)
|
||||
expect fun complexNestedAnnotations()
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("2.2")
|
||||
)
|
||||
)
|
||||
expect fun complexNestedAnnotationsNotMatch()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
package test
|
||||
|
||||
@ClassArgAnn(ClassForReference::class)
|
||||
actual fun getClassExpression() {}
|
||||
|
||||
@ClassArgAnn(ClassForReference::class)
|
||||
actual fun differentClassesWithSameName() {}
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
actual fun stringConstant() {}
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
actual fun stringConcatentation() {}
|
||||
|
||||
@StringArgAnn("1")
|
||||
actual fun constantFromInsideObject() {}
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
actual fun stringConcatentationWithProperty() {}
|
||||
|
||||
@EnumArgAnn(MyEnum.FOO)
|
||||
actual fun enumArg() {}
|
||||
|
||||
@VarargAnn("foo", "bar")
|
||||
actual fun varargInAnnotation() {}
|
||||
|
||||
@VarargAnn("foo", "bar")
|
||||
actual fun varargInAnnotationWithArraySpread() {}
|
||||
|
||||
@ArrayArgAnn(arrayOf("foo", "bar"))
|
||||
actual fun arrayInAnnotation() {}
|
||||
|
||||
@ArrayArgAnn(["foo"])
|
||||
actual fun arrayInAnnotationNotMatch() {}
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("2.2")
|
||||
)
|
||||
)
|
||||
actual fun complexNestedAnnotations() {}
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("DIFFERENT")
|
||||
)
|
||||
)
|
||||
actual fun complexNestedAnnotationsNotMatch() {}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
annotation class ClassArgAnn(val clazz: KClass<*>)
|
||||
|
||||
class ClassForReference {
|
||||
class ClassForReference
|
||||
}
|
||||
|
||||
@ClassArgAnn(ClassForReference::class)
|
||||
expect fun getClassExpression()
|
||||
|
||||
@ClassArgAnn(ClassForReference.ClassForReference::class)
|
||||
expect fun differentClassesWithSameName()
|
||||
|
||||
annotation class StringArgAnn(val s: String)
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
expect fun stringConstant()
|
||||
|
||||
@StringArgAnn("1" + ".9")
|
||||
expect fun stringConcatentation()
|
||||
|
||||
object Constants {
|
||||
const val STR = "1"
|
||||
}
|
||||
|
||||
@StringArgAnn(Constants.STR)
|
||||
expect fun constantFromInsideObject()
|
||||
|
||||
@StringArgAnn(Constants.STR + ".9")
|
||||
expect fun stringConcatentationWithProperty()
|
||||
|
||||
enum class MyEnum { FOO, BAR }
|
||||
|
||||
annotation class EnumArgAnn(val e: MyEnum)
|
||||
|
||||
@EnumArgAnn(MyEnum.FOO)
|
||||
expect fun enumArg()
|
||||
|
||||
annotation class VarargAnn(vararg val strings: String)
|
||||
|
||||
@VarargAnn("foo", "bar")
|
||||
expect fun varargInAnnotation()
|
||||
|
||||
@VarargAnn(*["foo", "bar"])
|
||||
expect fun varargInAnnotationWithArraySpread()
|
||||
|
||||
annotation class ArrayArgAnn(val strings: Array<String>)
|
||||
|
||||
@ArrayArgAnn(["foo", "bar"])
|
||||
expect fun arrayInAnnotation()
|
||||
|
||||
@ArrayArgAnn(["foo", "bar"])
|
||||
expect fun arrayInAnnotationNotMatch()
|
||||
|
||||
annotation class NestedAnnArg(val text: String, vararg val children: NestedAnnArg)
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("2.2")
|
||||
)
|
||||
)
|
||||
expect fun complexNestedAnnotations()
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("2.2")
|
||||
)
|
||||
)
|
||||
expect fun complexNestedAnnotationsNotMatch()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
package test
|
||||
|
||||
@ClassArgAnn(ClassForReference::class)
|
||||
actual fun getClassExpression() {}
|
||||
|
||||
@ClassArgAnn(ClassForReference::class)
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>differentClassesWithSameName<!>() {}
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
actual fun stringConstant() {}
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
actual fun stringConcatentation() {}
|
||||
|
||||
@StringArgAnn("1")
|
||||
actual fun constantFromInsideObject() {}
|
||||
|
||||
@StringArgAnn("1.9")
|
||||
actual fun stringConcatentationWithProperty() {}
|
||||
|
||||
@EnumArgAnn(MyEnum.FOO)
|
||||
actual fun enumArg() {}
|
||||
|
||||
@VarargAnn("foo", "bar")
|
||||
actual fun varargInAnnotation() {}
|
||||
|
||||
@VarargAnn("foo", "bar")
|
||||
actual fun varargInAnnotationWithArraySpread() {}
|
||||
|
||||
@ArrayArgAnn(arrayOf("foo", "bar"))
|
||||
actual fun arrayInAnnotation() {}
|
||||
|
||||
@ArrayArgAnn(["foo"])
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>arrayInAnnotationNotMatch<!>() {}
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("2.2")
|
||||
)
|
||||
)
|
||||
actual fun complexNestedAnnotations() {}
|
||||
|
||||
@NestedAnnArg(
|
||||
text = "root",
|
||||
NestedAnnArg("1"),
|
||||
NestedAnnArg("2",
|
||||
NestedAnnArg("2.1"),
|
||||
NestedAnnArg("DIFFERENT")
|
||||
)
|
||||
)
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>complexNestedAnnotationsNotMatch<!>() {}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// FIR_IDENTICAL
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann(val p: String = "")
|
||||
@Ann("")
|
||||
expect fun explicitDefaultArgument()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
// No special handling for this case
|
||||
@Ann
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>explicitDefaultArgument<!>() {}
|
||||
compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.fir.kt
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann<T>
|
||||
|
||||
class A
|
||||
class B
|
||||
private object FakeA {
|
||||
class A
|
||||
}
|
||||
|
||||
@Ann<A>
|
||||
expect fun sameTypeParam()
|
||||
|
||||
@Ann<B>
|
||||
expect fun differentTypeParam()
|
||||
|
||||
@Ann<FakeA.A>
|
||||
expect fun differentWithSameName()
|
||||
|
||||
@Ann<A?>
|
||||
expect fun nonNullvsNull()
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
expect fun differentVariance()
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
expect fun varianceVsNoVariance()
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
expect fun sameVariance()
|
||||
|
||||
@Ann<Ann<*>>
|
||||
expect fun startProjection()
|
||||
|
||||
annotation class ComplexNested<T>(
|
||||
vararg val anns: ComplexNested<*>,
|
||||
)
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<A>(),
|
||||
)
|
||||
expect fun complexSame()
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<B>(),
|
||||
)
|
||||
expect fun complexDiffer()
|
||||
|
||||
annotation class NestedWithSameTypeArgument<T>(
|
||||
vararg val anns: NestedWithSameTypeArgument<T>
|
||||
)
|
||||
|
||||
@NestedWithSameTypeArgument<A>(
|
||||
NestedWithSameTypeArgument()
|
||||
)
|
||||
expect fun explicitVsInfered()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
@Ann<A>
|
||||
actual fun sameTypeParam() {}
|
||||
|
||||
@Ann<A>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>differentTypeParam<!>() {}
|
||||
|
||||
@Ann<A>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>differentWithSameName<!>() {}
|
||||
|
||||
@Ann<A>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>nonNullvsNull<!>() {}
|
||||
|
||||
@Ann<Ann<out A>>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>differentVariance<!>() {}
|
||||
|
||||
@Ann<Ann<A>>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>varianceVsNoVariance<!>() {}
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
actual fun sameVariance() {}
|
||||
|
||||
@Ann<Ann<Any>>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>startProjection<!>() {}
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<A>(),
|
||||
)
|
||||
actual fun complexSame() {}
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<A>(),
|
||||
)
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>complexDiffer<!>() {}
|
||||
|
||||
@NestedWithSameTypeArgument<A>(
|
||||
NestedWithSameTypeArgument<A>()
|
||||
)
|
||||
actual fun explicitVsInfered() {}
|
||||
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann<T>
|
||||
|
||||
class A
|
||||
class B
|
||||
private object FakeA {
|
||||
class A
|
||||
}
|
||||
|
||||
@Ann<A>
|
||||
expect fun sameTypeParam()
|
||||
|
||||
@Ann<B>
|
||||
expect fun differentTypeParam()
|
||||
|
||||
@Ann<FakeA.A>
|
||||
expect fun differentWithSameName()
|
||||
|
||||
@Ann<A?>
|
||||
expect fun nonNullvsNull()
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
expect fun differentVariance()
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
expect fun varianceVsNoVariance()
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
expect fun sameVariance()
|
||||
|
||||
@Ann<Ann<*>>
|
||||
expect fun startProjection()
|
||||
|
||||
annotation class ComplexNested<T>(
|
||||
vararg val anns: ComplexNested<*>,
|
||||
)
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<A>(),
|
||||
)
|
||||
expect fun complexSame()
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<B>(),
|
||||
)
|
||||
expect fun complexDiffer()
|
||||
|
||||
annotation class NestedWithSameTypeArgument<T>(
|
||||
vararg val anns: NestedWithSameTypeArgument<T>
|
||||
)
|
||||
|
||||
@NestedWithSameTypeArgument<A>(
|
||||
NestedWithSameTypeArgument()
|
||||
)
|
||||
expect fun explicitVsInfered()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
@Ann<A>
|
||||
actual fun sameTypeParam() {}
|
||||
|
||||
@Ann<A>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>differentTypeParam<!>() {}
|
||||
|
||||
@Ann<A>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>differentWithSameName<!>() {}
|
||||
|
||||
@Ann<A>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>nonNullvsNull<!>() {}
|
||||
|
||||
@Ann<Ann<out A>>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>differentVariance<!>() {}
|
||||
|
||||
@Ann<Ann<A>>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>varianceVsNoVariance<!>() {}
|
||||
|
||||
@Ann<Ann<in A>>
|
||||
actual fun sameVariance() {}
|
||||
|
||||
@Ann<Ann<Any>>
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>startProjection<!>() {}
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<A>(),
|
||||
)
|
||||
actual fun complexSame() {}
|
||||
|
||||
@ComplexNested<A>(
|
||||
ComplexNested<A>(),
|
||||
ComplexNested<A>(),
|
||||
)
|
||||
actual fun complexDiffer() {}
|
||||
|
||||
@NestedWithSameTypeArgument<A>(
|
||||
NestedWithSameTypeArgument<A>()
|
||||
)
|
||||
actual fun explicitVsInfered() {}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// FIR_IDENTICAL
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann
|
||||
|
||||
@Ann
|
||||
expect class AnnotationMatching
|
||||
|
||||
@Ann
|
||||
expect class AnnotationOnExpectOnly
|
||||
|
||||
expect class AnnotationOnActualOnly
|
||||
|
||||
expect class AnnotationInside {
|
||||
@Ann
|
||||
fun matches()
|
||||
|
||||
@Ann
|
||||
fun onlyOnExpect()
|
||||
|
||||
fun onlyOnActual()
|
||||
}
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
@Ann
|
||||
actual class AnnotationMatching
|
||||
|
||||
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>AnnotationOnExpectOnly<!>
|
||||
|
||||
@Ann
|
||||
actual class AnnotationOnActualOnly
|
||||
|
||||
actual class AnnotationInside {
|
||||
@Ann
|
||||
actual fun matches() {}
|
||||
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onlyOnExpect<!>() {}
|
||||
|
||||
@Ann
|
||||
actual fun onlyOnActual() {}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// -- Module: <m1-common> --
|
||||
|
||||
// -- Module: <m1-jvm> --
|
||||
/jvm.kt:24:14: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.
|
||||
Expected: @Ann public final expect class OnClass defined in root package in file common.kt
|
||||
Actual: public final actual class OnClass defined in root package in file jvm.kt
|
||||
actual class OnClass
|
||||
^
|
||||
/jvm.kt:27:16: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.
|
||||
Expected: @Ann public final expect fun onMember(): Unit defined in OnMember
|
||||
Actual: public final actual fun onMember(): Unit defined in OnMember
|
||||
actual fun onMember() {}
|
||||
^
|
||||
/jvm.kt:34:18: warning: all annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.
|
||||
Expected: @Ann public final expect class ViaTypealias defined in root package in file common.kt
|
||||
Actual: public final class ViaTypealiasImpl defined in root package in file jvm.kt
|
||||
actual typealias ViaTypealias = ViaTypealiasImpl
|
||||
^
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/jvm.kt:(83,90): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.
|
||||
Expected: @Ann() public final expect class OnClass : Any
|
||||
Actual: public final actual class OnClass : Any
|
||||
|
||||
/jvm.kt:(131,139): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.
|
||||
Expected: @Ann() public final expect fun onMember(): Unit
|
||||
Actual: public final actual fun onMember(): Unit
|
||||
|
||||
/jvm.kt:(210,222): warning: All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.
|
||||
Expected: @Ann() public final expect class ViaTypealias : Any
|
||||
Actual: public final class ViaTypealiasImpl : Any
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
// FIR_IDENTICAL
|
||||
// RENDER_DIAGNOSTICS_FULL_TEXT
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann
|
||||
|
||||
@Ann
|
||||
expect class OnClass
|
||||
|
||||
expect class OnMember {
|
||||
@Ann
|
||||
fun onMember()
|
||||
}
|
||||
|
||||
@Ann
|
||||
expect class ViaTypealias {
|
||||
@Ann
|
||||
fun foo()
|
||||
}
|
||||
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>OnClass<!>
|
||||
|
||||
actual class OnMember {
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>onMember<!>() {}
|
||||
}
|
||||
|
||||
class ViaTypealiasImpl {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ViaTypealias<!> = ViaTypealiasImpl
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// FIR_IDENTICAL
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann
|
||||
|
||||
expect class CompatibleOverrides {
|
||||
fun foo()
|
||||
|
||||
@Ann
|
||||
fun foo(withArg: Any)
|
||||
}
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual class CompatibleOverrides {
|
||||
actual fun foo() {}
|
||||
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>foo<!>(withArg: Any) {}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann1
|
||||
annotation class Ann2
|
||||
|
||||
@Ann1
|
||||
@Ann2
|
||||
expect class AnnotationOrder
|
||||
|
||||
annotation class Ann3(vararg val numbers: Int)
|
||||
|
||||
@Ann3(1, 2)
|
||||
expect class ValuesOrderInsideAnnotationArgument
|
||||
|
||||
annotation class Ann4(val arg1: String, val arg2: String)
|
||||
|
||||
@Ann4(arg1 = "1", arg2 = "2")
|
||||
expect fun differentArgumentsOrder()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
|
||||
@Ann2
|
||||
@Ann1
|
||||
actual class AnnotationOrder
|
||||
|
||||
@Ann3(2, 1)
|
||||
actual class ValuesOrderInsideAnnotationArgument
|
||||
|
||||
@Ann4(arg2 = "2", arg1 = "1")
|
||||
actual fun differentArgumentsOrder() {}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann1
|
||||
annotation class Ann2
|
||||
|
||||
@Ann1
|
||||
@Ann2
|
||||
expect class AnnotationOrder
|
||||
|
||||
annotation class Ann3(vararg val numbers: Int)
|
||||
|
||||
@Ann3(1, 2)
|
||||
expect class ValuesOrderInsideAnnotationArgument
|
||||
|
||||
annotation class Ann4(val arg1: String, val arg2: String)
|
||||
|
||||
@Ann4(arg1 = "1", arg2 = "2")
|
||||
expect fun differentArgumentsOrder()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
|
||||
@Ann2
|
||||
@Ann1
|
||||
actual class AnnotationOrder
|
||||
|
||||
@Ann3(2, 1)
|
||||
actual class <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>ValuesOrderInsideAnnotationArgument<!>
|
||||
|
||||
@Ann4(arg2 = "2", arg1 = "1")
|
||||
actual fun differentArgumentsOrder() {}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann(val p: Double)
|
||||
|
||||
@Ann(0.3)
|
||||
expect fun floatNumbersComparison()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
@Ann(0.1 + 0.1 + 0.1)
|
||||
actual fun floatNumbersComparison() {}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann(val p: Double)
|
||||
|
||||
@Ann(0.3)
|
||||
expect fun floatNumbersComparison()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
@Ann(0.1 + 0.1 + 0.1)
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>floatNumbersComparison<!>() {}
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
annotation class Ann(val clazz: KClass<*>)
|
||||
|
||||
@Ann(LinkToExpectInnerClass.Inner::class)
|
||||
expect class LinkToExpectInnerClass {
|
||||
object Inner
|
||||
}
|
||||
|
||||
expect class WillBeTypealiased
|
||||
|
||||
@Ann(WillBeTypealiased::class)
|
||||
expect fun linkToExpectClassWhichWillBeTypealiased()
|
||||
|
||||
@Ann(WillBeTypealiased::class)
|
||||
expect fun linkToExpectClassWhichWillBeTypealiased2()
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
@Ann(LinkToExpectInnerClass.Inner::class)
|
||||
actual class LinkToExpectInnerClass {
|
||||
actual object Inner
|
||||
}
|
||||
|
||||
actual typealias WillBeTypealiased = Any
|
||||
|
||||
@Ann(WillBeTypealiased::class)
|
||||
actual fun linkToExpectClassWhichWillBeTypealiased() {}
|
||||
|
||||
@Ann(Any::class)
|
||||
actual fun linkToExpectClassWhichWillBeTypealiased2() {}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
expect annotation class JavaTypealiasAnnotationAnalogue
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
expect annotation class JavaTypealiasKotlinAnnotation
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias JavaTypealiasAnnotationAnalogue = JavaTypealiasAnnotationAnalogueImpl
|
||||
|
||||
actual typealias JavaTypealiasKotlinAnnotation = JavaTypealiasKotlinAnnotationImpl
|
||||
|
||||
// FILE: jvmJavaImpls.java
|
||||
import kotlin.annotation.AnnotationRetention;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface JavaTypealiasAnnotationAnalogueImpl {
|
||||
}
|
||||
|
||||
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
|
||||
public @interface JavaTypealiasKotlinAnnotationImpl {
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@Target(AnnotationTarget.TYPEALIAS, AnnotationTarget.CLASS)
|
||||
annotation class Ann
|
||||
|
||||
@Ann
|
||||
expect class KtTypealiasNotMatch
|
||||
|
||||
@Ann
|
||||
expect class AnnotationsNotConsideredOnTypealias
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
class KtTypealiasNotMatchImpl
|
||||
|
||||
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>KtTypealiasNotMatch<!> = KtTypealiasNotMatchImpl
|
||||
|
||||
class AnnotationsNotConsideredOnTypealiasImpl
|
||||
|
||||
@Ann
|
||||
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>AnnotationsNotConsideredOnTypealias<!> = AnnotationsNotConsideredOnTypealiasImpl
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
expect annotation class MyDeprecatedNotMatch
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
expect annotation class MyDeprecatedMatch
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias MyDeprecatedNotMatch = java.lang.Deprecated
|
||||
|
||||
actual typealias MyDeprecatedMatch = java.lang.Deprecated
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
expect annotation class MyDeprecatedNotMatch
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
expect annotation class MyDeprecatedMatch
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MyDeprecatedNotMatch<!> = java.lang.Deprecated
|
||||
|
||||
actual typealias MyDeprecatedMatch = java.lang.Deprecated
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
// removed target TYPEALIAS
|
||||
)
|
||||
expect annotation class MyDeprecatedNotMatch
|
||||
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.TYPEALIAS
|
||||
)
|
||||
expect annotation class MyDeprecatedMatch
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias MyDeprecatedNotMatch = kotlin.Deprecated
|
||||
|
||||
actual typealias MyDeprecatedMatch = kotlin.Deprecated
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
// removed target TYPEALIAS
|
||||
)
|
||||
expect annotation class MyDeprecatedNotMatch
|
||||
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.TYPEALIAS
|
||||
)
|
||||
expect annotation class MyDeprecatedMatch
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>MyDeprecatedNotMatch<!> = kotlin.Deprecated
|
||||
|
||||
actual typealias MyDeprecatedMatch = kotlin.Deprecated
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann
|
||||
|
||||
<!INCOMPATIBLE_MATCHING{JVM}!>@Ann
|
||||
expect inline fun hasWeakIncompatibility()<!>
|
||||
|
||||
<!INCOMPATIBLE_MATCHING{JVM}, INCOMPATIBLE_MATCHING{JVM}!>@Ann
|
||||
expect fun hasStrongIncompatibility(arg: Int)<!>
|
||||
|
||||
expect fun hasStrongIncompatibility(arg: Double)
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT, ACTUAL_WITHOUT_EXPECT!>hasWeakIncompatibility<!>() {}
|
||||
|
||||
actual fun <!ACTUAL_WITHOUT_EXPECT!>hasStrongIncompatibility<!>(arg: Any?) {}
|
||||
|
||||
actual fun hasStrongIncompatibility(arg: Double) {}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
annotation class Ann
|
||||
|
||||
@Ann
|
||||
expect inline fun hasWeakIncompatibility()
|
||||
|
||||
@Ann
|
||||
expect fun hasStrongIncompatibility<!NO_ACTUAL_FOR_EXPECT{JVM}!>(arg: Int)<!>
|
||||
|
||||
expect fun hasStrongIncompatibility(arg: Double)
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
<!ACTUAL_WITHOUT_EXPECT!>actual<!> fun <!ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT!>hasWeakIncompatibility<!>() {}
|
||||
|
||||
actual fun hasStrongIncompatibility<!ACTUAL_WITHOUT_EXPECT!>(arg: Any?)<!> {}
|
||||
|
||||
actual fun hasStrongIncompatibility(arg: Double) {}
|
||||
+2
-1
@@ -1,12 +1,13 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@file:OptIn(ExperimentalMultiplatform::class)
|
||||
|
||||
expect annotation class ActualOnly
|
||||
|
||||
@RequiresOptIn
|
||||
<!EXPECT_ACTUAL_OPT_IN_ANNOTATION!>expect<!> annotation class Both
|
||||
|
||||
@OptIn(ExperimentalMultiplatform::class)
|
||||
@RequiresOptIn
|
||||
@OptionalExpectation
|
||||
expect annotation class MyOptIn
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// WITH_STDLIB
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
@file:OptIn(ExperimentalMultiplatform::class)
|
||||
|
||||
expect annotation class ActualOnly
|
||||
|
||||
@RequiresOptIn
|
||||
<!EXPECT_ACTUAL_OPT_IN_ANNOTATION{JVM}!>expect<!> annotation class Both
|
||||
|
||||
@OptIn(ExperimentalMultiplatform::class)
|
||||
@RequiresOptIn
|
||||
@OptionalExpectation
|
||||
expect annotation class MyOptIn
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@OptionalExpectation
|
||||
expect annotation class A()
|
||||
|
||||
expect class C {
|
||||
class C {
|
||||
@A
|
||||
fun f()
|
||||
fun f() {}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
actual class C {
|
||||
actual fun f() {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
actual annotation class A
|
||||
|
||||
actual class C {
|
||||
@A
|
||||
actual fun f() {}
|
||||
}
|
||||
|
||||
Generated
+94
@@ -22750,6 +22750,100 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class AnnotationMatching {
|
||||
@Test
|
||||
public void testAllFilesPresentInAnnotationMatching() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsConstExpressions.kt")
|
||||
public void testAnnotationArgumentsConstExpressions() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsDefaults.kt")
|
||||
public void testAnnotationArgumentsDefaults() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationTypeParameters.kt")
|
||||
public void testAnnotationTypeParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicOnDeclaration.kt")
|
||||
public void testBasicOnDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("checkDiagnosticFullText.kt")
|
||||
public void testCheckDiagnosticFullText() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compatibleOverrides.kt")
|
||||
public void testCompatibleOverrides() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentOrder.kt")
|
||||
public void testDifferentOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("floatNumbersComparison.kt")
|
||||
public void testFloatNumbersComparison() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kclassArgWithExpectClass.kt")
|
||||
public void testKclassArgWithExpectClass() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnaloguesForJavaAnnotations.kt")
|
||||
public void testKotlinAnaloguesForJavaAnnotations() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealias.kt")
|
||||
public void testTypealias() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToJavaLibrary.kt")
|
||||
public void testTypealiasToJavaLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToKtLibrary.kt")
|
||||
public void testTypealiasToKtLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withOtherIncomatibilities.kt")
|
||||
public void testWithOtherIncomatibilities() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
Reference in New Issue
Block a user