[FIR] Add TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER check
This commit is contained in:
committed by
TeamCityServer
parent
470993ac07
commit
03215f4e0a
+2
@@ -324,6 +324,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
|
||||
val TYPE_PARAMETERS_NOT_ALLOWED by error<FirSourceElement, KtDeclaration>()
|
||||
|
||||
val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error<FirSourceElement, KtTypeParameter>()
|
||||
|
||||
val RETURN_TYPE_MISMATCH by error<FirSourceElement, KtExpression>(PositioningStrategy.WHOLE_ELEMENT) {
|
||||
parameter<ConeKotlinType>("expected")
|
||||
parameter<ConeKotlinType>("actual")
|
||||
|
||||
@@ -238,6 +238,7 @@ object FirErrors {
|
||||
val BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED by error0<FirSourceElement, KtTypeReference>()
|
||||
val REIFIED_TYPE_PARAMETER_NO_INLINE by error0<FirSourceElement, PsiElement>()
|
||||
val TYPE_PARAMETERS_NOT_ALLOWED by error0<FirSourceElement, KtDeclaration>()
|
||||
val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error0<FirSourceElement, KtTypeParameter>()
|
||||
val RETURN_TYPE_MISMATCH by error2<FirSourceElement, KtExpression, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
|
||||
|
||||
// Reflection
|
||||
|
||||
+37
@@ -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.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
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.scopes.impl.toConeType
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
|
||||
object FirPropertyTypeParametersChecker : FirPropertyChecker() {
|
||||
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val boundsByName = declaration.typeParameters.map { it.name to it.bounds }.toMap()
|
||||
val usedTypes = HashSet<ConeKotlinType>()
|
||||
fun collectAllTypes(type: ConeKotlinType) {
|
||||
if (usedTypes.add(type)) {
|
||||
type.typeArguments.forEach { it.type?.let(::collectAllTypes) }
|
||||
if (type is ConeTypeParameterType) {
|
||||
boundsByName[type.lookupTag.name]?.forEach { collectAllTypes(it.coneType) }
|
||||
}
|
||||
}
|
||||
}
|
||||
declaration.receiverTypeRef?.let { collectAllTypes(it.coneType) }
|
||||
|
||||
val usedNames = usedTypes.filterIsInstance<ConeTypeParameterType>().map { it.lookupTag.name }
|
||||
declaration.typeParameters.filterNot { usedNames.contains(it.name) }.forEach { danglingParam ->
|
||||
reporter.reportOn(danglingParam.source, FirErrors.TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, context)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -229,6 +229,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_N
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_REIFIED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_ON_LHS_OF_DOT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNEXPECTED_SAFE_CALL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_COMPANION
|
||||
@@ -504,6 +505,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
|
||||
map.put(TYPE_PARAMETERS_NOT_ALLOWED, "Type parameters are not allowed here")
|
||||
|
||||
map.put(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, "Type parameter of a property must be used in its receiver type")
|
||||
|
||||
map.put(RETURN_TYPE_MISMATCH, "Return type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE)
|
||||
|
||||
// Reflection
|
||||
|
||||
+2
@@ -42,6 +42,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirDestructuringDeclarationChecker,
|
||||
FirConstPropertyChecker,
|
||||
FirPropertyAccessorChecker,
|
||||
FirPropertyTypeParametersChecker,
|
||||
FirPropertyAccessorChecker,
|
||||
FirInitializerTypeMismatchChecker
|
||||
)
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ interface B {
|
||||
}
|
||||
|
||||
interface G<X> {
|
||||
val <X> boo: Double where X : A, X : B
|
||||
val <A> bal: Double where A : B
|
||||
val <Y> bas: Double where Y : B, <!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>X<!> : B
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>X<!>> boo: Double where X : A, X : B
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>A<!>> bal: Double where A : B
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>Y<!>> bas: Double where Y : B, <!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>X<!> : B
|
||||
}
|
||||
|
||||
class C() : A(), B
|
||||
@@ -66,4 +66,4 @@ val t1 = test2<A>(<!ARGUMENT_TYPE_MISMATCH!>A()<!>)
|
||||
val t2 = test2<B>(<!ARGUMENT_TYPE_MISMATCH!>C()<!>)
|
||||
val t3 = test2<C>(C())
|
||||
|
||||
val <T, B : T> x : Int = 0
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>B : T<!>> x : Int = 0
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!MUST_BE_INITIALIZED!>val <T : <!UNRESOLVED_REFERENCE!>KClass<T>.something<!>> abc<!>
|
||||
<!MUST_BE_INITIALIZED!>val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T : <!UNRESOLVED_REFERENCE!>KClass<T>.something<!><!>> abc<!>
|
||||
|
||||
@@ -43,7 +43,7 @@ abstract class MyAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalGenericClass1<!><T> : MyTrait<T>, MyAbstractClass<T>() {}
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalGenericClass2<!><T, R>(r : R) : MyTrait<T>, MyAbstractClass<R>() {
|
||||
override fun foo(r: R) = r
|
||||
override val <T> pr : R = r
|
||||
override val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T<!>> pr : R = r
|
||||
}
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass1<!> : MyTrait<Int>, MyAbstractClass<String>() {}
|
||||
abstract class MyLegalAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {}
|
||||
@@ -51,10 +51,10 @@ abstract class MyLegalAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass2<!><T>(t : T) : MyTrait<Int>, MyAbstractClass<Int>() {
|
||||
fun foo(t: T) = t
|
||||
fun bar(t: T) = t
|
||||
val <R> pr : T = t
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>R<!>> pr : T = t
|
||||
}
|
||||
abstract class MyLegalAbstractClass2<T>(t : T) : MyTrait<Int>, MyAbstractClass<Int>() {
|
||||
fun foo(t: T) = t
|
||||
fun bar(t: T) = t
|
||||
val <R> pr : T = t
|
||||
}
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>R<!>> pr : T = t
|
||||
}
|
||||
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
fun <T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!>> foo() {}
|
||||
|
||||
val <T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!>> bar = fun (x: Int): String { return x.toString() }
|
||||
|
||||
class A<T> where T : <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Double.(Int) -> Unit<!>
|
||||
|
||||
interface B<T, U : <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>T.() -> Unit<!>>
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun <T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!>> foo() {}
|
||||
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!><!>> bar = fun (x: Int): String { return x.toString() }
|
||||
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
fun <T: (Int) -> String> foo() {}
|
||||
|
||||
val <T: (kotlin.Int) -> kotlin.String> bar = fun (x: Int): String { return x.toString() }
|
||||
|
||||
class A<T, U, V> where T : () -> Unit, U : (Int) -> Double, V : (T, U) -> U
|
||||
|
||||
interface B<T, U : (T) -> Unit>
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun <T: (Int) -> String> foo() {}
|
||||
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T: (kotlin.Int) -> kotlin.String<!>> bar = fun (x: Int): String { return x.toString() }
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
// !DIAGNOSTICS: -REDUNDANT_PROJECTION -CONFLICTING_PROJECTION
|
||||
|
||||
interface G
|
||||
|
||||
val <T> T.a: Int
|
||||
get() = 3
|
||||
|
||||
val <T1, T2> Map<T1, T2>.b: String
|
||||
get() = "asds"
|
||||
|
||||
val <T : G> G.c: Int get() = 5
|
||||
|
||||
val <T1, T2, T3> List<Map<T2, T3>>.d: Int get() = 6
|
||||
|
||||
val <T: Any> G.e: T?
|
||||
get() = null
|
||||
|
||||
val <T> List<Map<Int, Map<String, T>>>.f: Int get() = 7
|
||||
|
||||
val <T> List<Map<Int, Map<String, out T>>>.g: Int get() = 7
|
||||
val <T> List<Map<Int, Map<String, in T>>>.h: Int get() = 7
|
||||
|
||||
val <T> List<Map<T, Map<T, T>>>.i: Int get() = 7
|
||||
|
||||
var <T1, T2, T3, T4> p = 1
|
||||
|
||||
class C<T1, T2> {
|
||||
val <E> T1.a: Int get() = 3
|
||||
val <E> T2.b: Int get() = 3
|
||||
val <E> E.c: Int get() = 3
|
||||
val <E> Map<T1, T2>.d: Int get() = 3
|
||||
val <E> Map<T1, E>.e: Int get() = 3
|
||||
}
|
||||
|
||||
val <T : Enum<T>> T.z1: Int
|
||||
get() = 4
|
||||
|
||||
interface D<T : Enum<T>>
|
||||
|
||||
val <X: D<*>> X.z2: Int
|
||||
get() = 4
|
||||
|
||||
val <Y> D<*>.z3: Int
|
||||
get() = 4
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -REDUNDANT_PROJECTION -CONFLICTING_PROJECTION
|
||||
|
||||
interface G
|
||||
|
||||
Vendored
-28
@@ -1,28 +0,0 @@
|
||||
|
||||
val <T : K, K> K.a: Int get() = 4
|
||||
|
||||
val <T, K> K.b: Int where T : K
|
||||
get() = 4
|
||||
|
||||
val <T, K> K.c: Int where T : List<K>
|
||||
get() = 4
|
||||
|
||||
val <T, K> K.d: Int where K : T
|
||||
get() = 4
|
||||
|
||||
val <T, K> K.e: Int where K : List<T>
|
||||
get() = 4
|
||||
|
||||
interface G
|
||||
val <T> G.x1: Int where T : G
|
||||
get() = 4
|
||||
|
||||
|
||||
val <X, Y, Z> Z.x2: Int where X : Y, Z : Y
|
||||
get() = 4
|
||||
|
||||
val <X, Y: Map<Z, X>, Z: List<List<Y>>> Z.x3: Int
|
||||
get() = 5
|
||||
|
||||
val <X, Y: Map<X, List<Z>>, Z> Map<X, List<Y>>.x4: Int
|
||||
get() = 5
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T : K<!>, K> K.a: Int get() = 4
|
||||
|
||||
|
||||
+6
@@ -1004,6 +1004,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER) { firDiagnostic ->
|
||||
TypeParameterOfPropertyNotUsedInReceiverImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.RETURN_TYPE_MISMATCH) { firDiagnostic ->
|
||||
ReturnTypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
|
||||
+4
@@ -713,6 +713,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = TypeParametersNotAllowed::class
|
||||
}
|
||||
|
||||
abstract class TypeParameterOfPropertyNotUsedInReceiver : KtFirDiagnostic<KtTypeParameter>() {
|
||||
override val diagnosticClass get() = TypeParameterOfPropertyNotUsedInReceiver::class
|
||||
}
|
||||
|
||||
abstract class ReturnTypeMismatch : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = ReturnTypeMismatch::class
|
||||
abstract val expected: KtType
|
||||
|
||||
+7
@@ -1152,6 +1152,13 @@ internal class TypeParametersNotAllowedImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class TypeParameterOfPropertyNotUsedInReceiverImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.TypeParameterOfPropertyNotUsedInReceiver(), KtAbstractFirDiagnostic<KtTypeParameter> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ReturnTypeMismatchImpl(
|
||||
override val expected: KtType,
|
||||
override val actual: KtType,
|
||||
|
||||
Reference in New Issue
Block a user