diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt index 51791ec72d4..cf980bfc6bf 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt @@ -174,5 +174,9 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { ) val SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val CONCURRENT_HASH_MAP_CONTAINS_OPERATOR by deprecationError(ProhibitConcurrentHashMapContains) + val SPREAD_ON_SIGNATURE_POLYMORPHIC_CALL by deprecationError( + ProhibitSpreadOnSignaturePolymorphicCall, + PositioningStrategy.SPREAD_OPERATOR + ) } } diff --git a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt index 02f4286efd6..81c806a588d 100644 --- a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt +++ b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature.DefaultMethodsCallFromJava6TargetError import org.jetbrains.kotlin.config.LanguageFeature.ProhibitConcurrentHashMapContains import org.jetbrains.kotlin.config.LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses +import org.jetbrains.kotlin.config.LanguageFeature.ProhibitSpreadOnSignaturePolymorphicCall import org.jetbrains.kotlin.config.LanguageFeature.RepeatableAnnotationContainerConstraints import org.jetbrains.kotlin.fir.analysis.diagnostics.* import org.jetbrains.kotlin.fir.analysis.diagnostics.SourceElementPositioningStrategies @@ -118,5 +119,6 @@ object FirJvmErrors { val INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET by deprecationError0(DefaultMethodsCallFromJava6TargetError, SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val CONCURRENT_HASH_MAP_CONTAINS_OPERATOR by deprecationError0(ProhibitConcurrentHashMapContains) + val SPREAD_ON_SIGNATURE_POLYMORPHIC_CALL by deprecationError0(ProhibitSpreadOnSignaturePolymorphicCall, SourceElementPositioningStrategies.SPREAD_OPERATOR) } diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt index 91d29ba7269..67cb5a898ce 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt @@ -24,7 +24,8 @@ object JvmExpressionCheckers : ExpressionCheckers() { FirJavaGenericVarianceViolationTypeChecker, FirSuperCallWithDefaultsChecker, FirJvmSuspensionPointInsideMutexLockChecker, - FirJvmInconsistentOperatorFromJavaCallChecker + FirJvmInconsistentOperatorFromJavaCallChecker, + FirJvmPolymorphicSignatureCallChecker ) override val annotationCheckers: Set diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJvmPolymorphicSignatureCallChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJvmPolymorphicSignatureCallChecker.kt new file mode 100644 index 00000000000..4f93392c545 --- /dev/null +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJvmPolymorphicSignatureCallChecker.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression + +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId +import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.name.ClassId + +object FirJvmPolymorphicSignatureCallChecker : FirFunctionCallChecker() { + private val polymorphicSignatureClassId = ClassId.fromString("java/lang/invoke/MethodHandle.PolymorphicSignature") + + override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) { + if (!context.session.languageVersionSettings.supportsFeature(LanguageFeature.PolymorphicSignature)) return + val callableSymbol = expression.calleeReference.toResolvedCallableSymbol() ?: return + if (callableSymbol.getAnnotationByClassId(polymorphicSignatureClassId) == null) return + + for (valueArgument in expression.arguments) { + if (valueArgument is FirVarargArgumentsExpression) { + for (argument in valueArgument.arguments) { + if (argument is FirSpreadArgumentExpression) { + reporter.reportOn(argument.source, FirJvmErrors.SPREAD_ON_SIGNATURE_POLYMORPHIC_CALL, context) + } + } + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt index 53fb9360203..47cbc2c534c 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.jvm.diagnostics +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE @@ -68,6 +69,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATED_ANNOTATION_TARGET6 import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATED_ANNOTATION_WITH_CONTAINER +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SPREAD_ON_SIGNATURE_POLYMORPHIC_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.STRICTFP_ON_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SUPER_CALL_WITH_DEFAULT_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SUSPENSION_POINT_INSIDE_CRITICAL_SECTION @@ -270,6 +272,10 @@ object FirJvmDefaultErrorMessages { "Use explicit form of the call to 'containsKey'/'containsValue'/'contains' or cast the value to kotlin.collections.Map instead. " + "See https://youtrack.jetbrains.com/issue/KT-18053 for more details" ) + map.put( + SPREAD_ON_SIGNATURE_POLYMORPHIC_CALL, + "Spread operator is prohibited for arguments to signature-polymorphic calls" + ) } } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_after.fir.kt b/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_after.fir.kt deleted file mode 100644 index f39d060eb3b..00000000000 --- a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_after.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -// !LANGUAGE: +PolymorphicSignature +ProhibitSpreadOnSignaturePolymorphicCall -// FULL_JDK - -import java.lang.invoke.MethodHandle - -fun test(mh: MethodHandle) { - mh.invokeExact("1", "2") - mh.invokeExact(*emptyArray(), "X") - mh.invokeExact(*arrayOf("A", "B"), "C", *arrayOf("D", "E")) - mh.invoke(*arrayOf("A")) -} diff --git a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_after.kt b/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_after.kt index b6a6fe669ed..12459b6d5fc 100644 --- a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_after.kt +++ b/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_after.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +PolymorphicSignature +ProhibitSpreadOnSignaturePolymorphicCall // FULL_JDK diff --git a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_before.fir.kt b/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_before.fir.kt deleted file mode 100644 index ecd5ebbe4d6..00000000000 --- a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_before.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -// !LANGUAGE: +PolymorphicSignature -ProhibitSpreadOnSignaturePolymorphicCall -// FULL_JDK - -import java.lang.invoke.MethodHandle - -fun test(mh: MethodHandle) { - mh.invokeExact("1", "2") - mh.invokeExact(*emptyArray(), "X") - mh.invokeExact(*arrayOf("A", "B"), "C", *arrayOf("D", "E")) - mh.invoke(*arrayOf("A")) -} diff --git a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_before.kt b/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_before.kt index 42c7f094034..8df9b5e39a9 100644 --- a/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_before.kt +++ b/compiler/testData/diagnostics/tests/j+k/polymorphicSignature/spreadOperator_before.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +PolymorphicSignature -ProhibitSpreadOnSignaturePolymorphicCall // FULL_JDK diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index d09cec96f48..b2f11ac5734 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -4059,4 +4059,16 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJvmErrors.SPREAD_ON_SIGNATURE_POLYMORPHIC_CALL.errorFactory) { firDiagnostic -> + SpreadOnSignaturePolymorphicCallErrorImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirJvmErrors.SPREAD_ON_SIGNATURE_POLYMORPHIC_CALL.warningFactory) { firDiagnostic -> + SpreadOnSignaturePolymorphicCallWarningImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index a33efb46346..7f4f3619a5b 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2824,4 +2824,12 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ConcurrentHashMapContainsOperatorWarning::class } + abstract class SpreadOnSignaturePolymorphicCallError : KtFirDiagnostic() { + override val diagnosticClass get() = SpreadOnSignaturePolymorphicCallError::class + } + + abstract class SpreadOnSignaturePolymorphicCallWarning : KtFirDiagnostic() { + override val diagnosticClass get() = SpreadOnSignaturePolymorphicCallWarning::class + } + } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index b48329e6d5b..62c1103179e 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -4595,3 +4595,17 @@ internal class ConcurrentHashMapContainsOperatorWarningImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class SpreadOnSignaturePolymorphicCallErrorImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.SpreadOnSignaturePolymorphicCallError(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class SpreadOnSignaturePolymorphicCallWarningImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.SpreadOnSignaturePolymorphicCallWarning(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} +