[FIR] Add FirDelegateUsesExtensionPropertyTypeParameterChecker

This commit is contained in:
Nikolay Lunyak
2021-09-29 15:20:52 +03:00
committed by TeamCityServer
parent f97e666608
commit dbfe3524ce
11 changed files with 103 additions and 44 deletions
@@ -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),
@@ -1749,6 +1749,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val actualType: KtType
}
abstract class DelegateUsesExtensionPropertyTypeParameter : KtFirDiagnostic<KtProperty>() {
override val diagnosticClass get() = DelegateUsesExtensionPropertyTypeParameter::class
}
abstract class DelegateUsesExtensionPropertyTypeParameterWarning : KtFirDiagnostic<KtProperty>() {
override val diagnosticClass get() = DelegateUsesExtensionPropertyTypeParameterWarning::class
}
abstract class InitializerTypeMismatch : KtFirDiagnostic<KtProperty>() {
override val diagnosticClass get() = InitializerTypeMismatch::class
abstract val expectedType: KtType
@@ -2103,6 +2103,16 @@ internal class WrongSetterParameterTypeImpl(
override val token: ValidityToken,
) : KtFirDiagnostic.WrongSetterParameterType(), KtAbstractFirDiagnostic<KtTypeReference>
internal class DelegateUsesExtensionPropertyTypeParameterImpl(
override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.DelegateUsesExtensionPropertyTypeParameter(), KtAbstractFirDiagnostic<KtProperty>
internal class DelegateUsesExtensionPropertyTypeParameterWarningImpl(
override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.DelegateUsesExtensionPropertyTypeParameterWarning(), KtAbstractFirDiagnostic<KtProperty>
internal class InitializerTypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,
@@ -891,6 +891,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER by error<KtProperty>(PositioningStrategy.PROPERTY_DELEGATE)
val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER_WARNING by warning<KtProperty>(PositioningStrategy.PROPERTY_DELEGATE)
val INITIALIZER_TYPE_MISMATCH by error<KtProperty>(PositioningStrategy.PROPERTY_INITIALIZER) {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
@@ -487,6 +487,8 @@ object FirErrors {
val CONST_VAL_WITHOUT_INITIALIZER by error0<KtProperty>(SourceElementPositioningStrategies.CONST_MODIFIER)
val CONST_VAL_WITH_NON_CONST_INITIALIZER by error0<KtExpression>()
val WRONG_SETTER_PARAMETER_TYPE by error2<KtTypeReference, ConeKotlinType, ConeKotlinType>()
val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER by error0<KtProperty>(SourceElementPositioningStrategies.PROPERTY_DELEGATE)
val DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER_WARNING by warning0<KtProperty>(SourceElementPositioningStrategies.PROPERTY_DELEGATE)
val INITIALIZER_TYPE_MISMATCH by error3<KtProperty, ConeKotlinType, ConeKotlinType, Boolean>(SourceElementPositioningStrategies.PROPERTY_INITIALIZER)
val GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
val SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
@@ -60,6 +60,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirInlinePropertyChecker,
FirPropertyFromParameterChecker,
FirLocalVariableTypeParametersSyntaxChecker,
FirDelegateUsesExtensionPropertyTypeParameterChecker,
)
override val backingFieldCheckers: Set<FirBackingFieldChecker>
@@ -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<FirFunctionCall>() ?: 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<FirTypeParameterSymbol>,
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
}
}
@@ -1,22 +0,0 @@
// !LANGUAGE: +ForbidUsingExtensionPropertyTypeParameterInDelegate
class Delegate<T : Any> {
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 <T : Any> List<T>.foo by Delegate<T>()
class Wrapper<T>(val v: T? = null)
operator fun <T> Wrapper<T>.getValue(thisRef: Any?, kp: Any?): T = v!!
val <T : Any> List<T>.bar by Wrapper<T>()
fun useString(s: String) {}
fun main(listInt: List<Int>, listStr: List<String>) {
listInt.foo = 42
useString(listStr.foo) // CCE
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +ForbidUsingExtensionPropertyTypeParameterInDelegate
class Delegate<T : Any> {
@@ -1,22 +0,0 @@
// !LANGUAGE: -ForbidUsingExtensionPropertyTypeParameterInDelegate
class Delegate<T : Any> {
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 <T : Any> List<T>.foo by Delegate<T>()
class Wrapper<T>(val v: T? = null)
operator fun <T> Wrapper<T>.getValue(thisRef: Any?, kp: Any?): T = v!!
val <T : Any> List<T>.bar by Wrapper<T>()
fun useString(s: String) {}
fun main(listInt: List<Int>, listStr: List<String>) {
listInt.foo = 42
useString(listStr.foo) // CCE
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -ForbidUsingExtensionPropertyTypeParameterInDelegate
class Delegate<T : Any> {