diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 8a139289791..3b04713247d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -2471,6 +2471,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER) { firDiagnostic -> + DelegateUsesExtensionPropertyTypeParameterImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER_WARNING) { firDiagnostic -> + DelegateUsesExtensionPropertyTypeParameterWarningImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.INITIALIZER_TYPE_MISMATCH) { firDiagnostic -> InitializerTypeMismatchImpl( firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 33a105859c5..d8a08adfb6b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1749,6 +1749,14 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val actualType: KtType } + abstract class DelegateUsesExtensionPropertyTypeParameter : KtFirDiagnostic() { + override val diagnosticClass get() = DelegateUsesExtensionPropertyTypeParameter::class + } + + abstract class DelegateUsesExtensionPropertyTypeParameterWarning : KtFirDiagnostic() { + override val diagnosticClass get() = DelegateUsesExtensionPropertyTypeParameterWarning::class + } + abstract class InitializerTypeMismatch : KtFirDiagnostic() { override val diagnosticClass get() = InitializerTypeMismatch::class abstract val expectedType: KtType diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index e74397bf531..bb5263d876d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2103,6 +2103,16 @@ internal class WrongSetterParameterTypeImpl( override val token: ValidityToken, ) : KtFirDiagnostic.WrongSetterParameterType(), KtAbstractFirDiagnostic +internal class DelegateUsesExtensionPropertyTypeParameterImpl( + override val firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.DelegateUsesExtensionPropertyTypeParameter(), KtAbstractFirDiagnostic + +internal class DelegateUsesExtensionPropertyTypeParameterWarningImpl( + override val firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.DelegateUsesExtensionPropertyTypeParameterWarning(), KtAbstractFirDiagnostic + internal class InitializerTypeMismatchImpl( override val expectedType: KtType, override val actualType: KtType, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index f749cee58c2..b529cc5df53 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -891,6 +891,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("expectedType") parameter("actualType") } + val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER by error(PositioningStrategy.PROPERTY_DELEGATE) + val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER_WARNING by warning(PositioningStrategy.PROPERTY_DELEGATE) val INITIALIZER_TYPE_MISMATCH by error(PositioningStrategy.PROPERTY_INITIALIZER) { parameter("expectedType") parameter("actualType") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index eda3f8af45b..c303a132eb5 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -487,6 +487,8 @@ object FirErrors { val CONST_VAL_WITHOUT_INITIALIZER by error0(SourceElementPositioningStrategies.CONST_MODIFIER) val CONST_VAL_WITH_NON_CONST_INITIALIZER by error0() val WRONG_SETTER_PARAMETER_TYPE by error2() + val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER by error0(SourceElementPositioningStrategies.PROPERTY_DELEGATE) + val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER_WARNING by warning0(SourceElementPositioningStrategies.PROPERTY_DELEGATE) val INITIALIZER_TYPE_MISMATCH by error3(SourceElementPositioningStrategies.PROPERTY_INITIALIZER) val GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY by error0(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) val SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY by error0(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 01b03ae4dac..617abae8d2c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -60,6 +60,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirInlinePropertyChecker, FirPropertyFromParameterChecker, FirLocalVariableTypeParametersSyntaxChecker, + FirDelegateUsesExtensionPropertyTypeParameterChecker, ) override val backingFieldCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt new file mode 100644 index 00000000000..ae9e43d9821 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegateUsesExtensionPropertyTypeParameterChecker.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2010-2020 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.checkers.declaration + +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0 +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +object FirDelegateUsesExtensionPropertyTypeParameterChecker : FirPropertyChecker() { + override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { + val delegate = declaration.delegate.safeAs() ?: return + val parameters = declaration.typeParameters.mapTo(hashSetOf()) { it.symbol } + + val shouldReportError = delegate.typeRef.coneType.containsTypeParameterFrom(parameters, delegate, context, reporter) + + if (shouldReportError) { + val diagnostic = getProperDiagnostic(context) + reporter.reportOn(declaration.source, diagnostic, context) + } + } + + private fun getProperDiagnostic(context: CheckerContext): FirDiagnosticFactory0 { + val reportAsError = context.session.languageVersionSettings.supportsFeature( + LanguageFeature.ForbidUsingExtensionPropertyTypeParameterInDelegate + ) + + return if (reportAsError) { + FirErrors.DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER + } else { + FirErrors.DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER_WARNING + } + } + + private fun ConeKotlinType.containsTypeParameterFrom( + parameters: HashSet, + delegate: FirFunctionCall, + context: CheckerContext, + reporter: DiagnosticReporter, + ): Boolean { + for (it in typeArguments) { + val theType = it.type ?: continue + val symbol = theType.toSymbol(context.session) + + if ( + symbol in parameters || + theType.containsTypeParameterFrom(parameters, delegate, context, reporter) + ) { + return true + } + } + + return false + } +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty.fir.kt b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty.fir.kt deleted file mode 100644 index 8785b1a6276..00000000000 --- a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty.fir.kt +++ /dev/null @@ -1,22 +0,0 @@ -// !LANGUAGE: +ForbidUsingExtensionPropertyTypeParameterInDelegate - -class Delegate { - private var v: T? = null - operator fun getValue(thisRef: Any?, kp: Any?): T = v!! - operator fun setValue(thisRef: Any?, kp: Any?, newValue: T) { v = newValue } -} - -var List.foo by Delegate() - -class Wrapper(val v: T? = null) - -operator fun Wrapper.getValue(thisRef: Any?, kp: Any?): T = v!! - -val List.bar by Wrapper() - -fun useString(s: String) {} - -fun main(listInt: List, listStr: List) { - listInt.foo = 42 - useString(listStr.foo) // CCE -} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty.kt b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty.kt index bae208c3a97..5fb06da2678 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +ForbidUsingExtensionPropertyTypeParameterInDelegate class Delegate { diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.fir.kt b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.fir.kt deleted file mode 100644 index a9b4d2ceb8c..00000000000 --- a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.fir.kt +++ /dev/null @@ -1,22 +0,0 @@ -// !LANGUAGE: -ForbidUsingExtensionPropertyTypeParameterInDelegate - -class Delegate { - private var v: T? = null - operator fun getValue(thisRef: Any?, kp: Any?): T = v!! - operator fun setValue(thisRef: Any?, kp: Any?, newValue: T) { v = newValue } -} - -var List.foo by Delegate() - -class Wrapper(val v: T? = null) - -operator fun Wrapper.getValue(thisRef: Any?, kp: Any?): T = v!! - -val List.bar by Wrapper() - -fun useString(s: String) {} - -fun main(listInt: List, listStr: List) { - listInt.foo = 42 - useString(listStr.foo) // CCE -} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt index 1d6573a6562..d3dcd36898f 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: -ForbidUsingExtensionPropertyTypeParameterInDelegate class Delegate {