FIR checker: report LOCAL_VARIABLE_WITH_TYPE_PARAMETERS

This commit is contained in:
Mark Punzalan
2021-08-25 07:22:34 +00:00
committed by TeamCityServer
parent a18daa5d62
commit 580f1d51f6
12 changed files with 137 additions and 41 deletions
@@ -866,6 +866,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
}
val ACCESSOR_FOR_DELEGATED_PROPERTY by error<KtPropertyAccessor>()
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error<KtModifierListOwner>(PositioningStrategy.ABSTRACT_MODIFIER)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
}
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
@@ -476,6 +476,8 @@ object FirErrors {
val WRONG_GETTER_RETURN_TYPE by error2<KtTypeReference, ConeKotlinType, ConeKotlinType>()
val ACCESSOR_FOR_DELEGATED_PROPERTY by error0<KtPropertyAccessor>()
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0<KtModifierListOwner>(SourceElementPositioningStrategies.ABSTRACT_MODIFIER)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
// Multi-platform projects
val EXPECTED_DECLARATION_WITH_BODY by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -12,10 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnonymousFunctionParametersChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirAnonymousFunctionSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirDelegationInInterfaceSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirFunctionTypeParametersSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirTypeParameterSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.*
object CommonDeclarationCheckers : DeclarationCheckers() {
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
@@ -59,6 +56,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirDelegatedPropertyChecker,
FirInlinePropertyChecker,
FirPropertyFromParameterChecker,
FirLocalVariableTypeParametersSyntaxChecker,
)
override val classCheckers: Set<FirClassChecker>
@@ -0,0 +1,56 @@
/*
* 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.syntax
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
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.analysis.diagnostics.typeParametersList
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtProperty
// KtExpression is the appropriate PsiElement type; local variables are used in increments/decrements of dot-qualified expressions.
object FirLocalVariableTypeParametersSyntaxChecker : FirDeclarationSyntaxChecker<FirProperty, KtExpression>() {
override fun isApplicable(element: FirProperty, source: FirSourceElement): Boolean =
source.kind !is FirFakeSourceElementKind && element.isLocal
override fun checkPsi(
element: FirProperty,
source: FirPsiSourceElement,
psi: KtExpression,
context: CheckerContext,
reporter: DiagnosticReporter
) {
if (psi is KtProperty && psi.typeParameterList != null) {
val diagnostic =
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitTypeParametersForLocalVariables))
FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS else FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING
reporter.reportOn(source, diagnostic, context)
}
}
override fun checkLightTree(
element: FirProperty,
source: FirSourceElement,
context: CheckerContext,
reporter: DiagnosticReporter
) {
source.treeStructure.typeParametersList(source.lighterASTNode)?.let { _ ->
val diagnostic =
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitTypeParametersForLocalVariables))
FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS else FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING
reporter.reportOn(source, diagnostic, context)
}
}
}
@@ -256,6 +256,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_L
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_ANNOTATION_CLASS_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_INTERFACE_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_OBJECT_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_CLASSES_IN_SUPERTYPE_LIST
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_COMPANION_OBJECTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED
@@ -1252,6 +1254,8 @@ class FirDefaultErrorMessages {
)
map.put(ACCESSOR_FOR_DELEGATED_PROPERTY, "Delegated property cannot have accessors with non-default implementations")
map.put(ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS, "This property cannot be declared abstract")
map.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING, "Type parameters for local variables are deprecated")
map.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS, "Local variables are not allowed to have type parameters")
map.put(CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, "Const 'val' are only allowed on top level or in objects")
map.put(CONST_VAL_WITH_GETTER, "Const 'val' should not have a getter")
@@ -9,6 +9,6 @@ class SomeClass {
val <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> T.field: Int get() = 12
fun foo() {
val <@A1 @A2(3) @A2 @A1(12) @A2("Test") T> localVal = 12
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><@A1 @A2(3) @A2 @A1(12) @A2("Test") T><!> localVal = 12
}
}
@@ -4,13 +4,13 @@
import kotlin.reflect.KProperty
fun test() {
val <T> a0 = 0
val <T : __UNRESOLVED__> a1 = ""
val <T : String> a2 = 0
<!WRONG_MODIFIER_TARGET!>const<!> val <T> a3 = 0
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> val <T> a4 = 0
val <T> a5 by Delegate<Int>()
val <T> a6 by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate<<!UNRESOLVED_REFERENCE!>T<!>>()<!>
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING!><T><!> a0 = 0
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING!><T : __UNRESOLVED__><!> a1 = ""
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING!><T : String><!> a2 = 0
<!WRONG_MODIFIER_TARGET!>const<!> val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING!><T><!> a3 = 0
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING!><T><!> a4 = 0
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING!><T><!> a5 by Delegate<Int>()
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING!><T><!> a6 by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate<<!UNRESOLVED_REFERENCE!>T<!>>()<!>
}
class Delegate<F> {
@@ -4,13 +4,13 @@
import kotlin.reflect.KProperty
fun test() {
val <T> a0 = 0
val <T : __UNRESOLVED__> a1 = ""
val <T : String> a2 = 0
<!WRONG_MODIFIER_TARGET!>const<!> val <T> a3 = 0
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> val <T> a4 = 0
val <T> a5 by Delegate<Int>()
val <T> a6 by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate<<!UNRESOLVED_REFERENCE!>T<!>>()<!>
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> a0 = 0
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : __UNRESOLVED__><!> a1 = ""
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : String><!> a2 = 0
<!WRONG_MODIFIER_TARGET!>const<!> val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> a3 = 0
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> a4 = 0
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> a5 by Delegate<Int>()
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> a6 by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate<<!UNRESOLVED_REFERENCE!>T<!>>()<!>
}
class Delegate<F> {
@@ -3,32 +3,32 @@
// TESTCASE NUMBER: 1
fun case_1() {
val <T> x1 = 1
var <T> x2 = 1
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x1 = 1
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x2 = 1
}
// TESTCASE NUMBER: 2
fun case_2() {
val <T> x1: Int = 1
var <T> x2: Int = 1
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x1: Int = 1
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x2: Int = 1
}
// TESTCASE NUMBER: 3
fun case_3() {
val <T> x1: Map<Int, Int> = mapOf(1 to 1)
var <T> x2: Map<Int, Int> = mapOf(1 to 1)
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x1: Map<Int, Int> = mapOf(1 to 1)
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x2: Map<Int, Int> = mapOf(1 to 1)
}
// TESTCASE NUMBER: 4
fun case_4() {
val <T> y1: Number where __UNRESOLVED__: __UNRESOLVED__ = 1
var <T> y2: Number where __UNRESOLVED__: __UNRESOLVED__ = 1
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> y1: Number where __UNRESOLVED__: __UNRESOLVED__ = 1
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> y2: Number where __UNRESOLVED__: __UNRESOLVED__ = 1
}
// TESTCASE NUMBER: 5
fun case_5() {
val <T : __UNRESOLVED__> x1: Map<Int, Int> = mapOf(1 to 1)
var <T : __UNRESOLVED__> x2: Map<Int, Int> = mapOf(1 to 1)
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : __UNRESOLVED__><!> x1: Map<Int, Int> = mapOf(1 to 1)
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : __UNRESOLVED__><!> x2: Map<Int, Int> = mapOf(1 to 1)
}
/*
@@ -51,19 +51,19 @@ fun case_7() {
// TESTCASE NUMBER: 8
fun case_8() {
val <A, B : A, C : B, D : C, E : D> x1 = 1
var <A, B : A, C : B, D : C, E : D> x2 = 2
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><A, B : A, C : B, D : C, E : D><!> x1 = 1
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><A, B : A, C : B, D : C, E : D><!> x2 = 2
}
// TESTCASE NUMBER: 9
fun case_9(y: Boolean?) = when (val <T> x = y) {
fun case_9(y: Boolean?) = when (val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x = y) {
true -> null
false -> null
null -> null
}
// TESTCASE NUMBER: 10
fun case_10(x: Boolean?) = when (val <T> x where T: suspend () -> Unit, T: Boolean = x) {
fun case_10(x: Boolean?) = when (val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x where T: suspend () -> Unit, T: Boolean = x) {
true -> null
false -> null
null -> null
@@ -71,24 +71,24 @@ fun case_10(x: Boolean?) = when (val <T> x where T: suspend () -> Unit, T: Boole
// TESTCASE NUMBER: 11
fun case_11() {
val <T> x by lazy { 1 }
var <T> x by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>lazy { 1 }<!>
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x by lazy { 1 }
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T><!> x by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>lazy { 1 }<!>
}
// TESTCASE NUMBER: 12
fun case_12() {
val <T : __UNRESOLVED__> x: Int
var <T : __UNRESOLVED__> x: Int
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : __UNRESOLVED__><!> x: Int
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : __UNRESOLVED__><!> x: Int
}
// TESTCASE NUMBER: 13
fun case_13() {
val <T : __UNRESOLVED__> x: Int where __UNRESOLVED__: __UNRESOLVED__
var <T : __UNRESOLVED__> x: Int where __UNRESOLVED__: __UNRESOLVED__
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : __UNRESOLVED__><!> x: Int where __UNRESOLVED__: __UNRESOLVED__
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : __UNRESOLVED__><!> x: Int where __UNRESOLVED__: __UNRESOLVED__
}
// TESTCASE NUMBER: 14
fun case_14() {
val <T : T> x1 = 1
var <T : T> x2 = 1
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : T><!> x1 = 1
var <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><T : T><!> x2 = 1
}
@@ -2385,6 +2385,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING) { firDiagnostic ->
LocalVariableWithTypeParametersWarningImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS) { firDiagnostic ->
LocalVariableWithTypeParametersImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.EXPECTED_DECLARATION_WITH_BODY) { firDiagnostic ->
ExpectedDeclarationWithBodyImpl(
firDiagnostic as FirPsiDiagnostic,
@@ -1686,6 +1686,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = AbstractPropertyInPrimaryConstructorParameters::class
}
abstract class LocalVariableWithTypeParametersWarning : KtFirDiagnostic<KtProperty>() {
override val diagnosticClass get() = LocalVariableWithTypeParametersWarning::class
}
abstract class LocalVariableWithTypeParameters : KtFirDiagnostic<KtProperty>() {
override val diagnosticClass get() = LocalVariableWithTypeParameters::class
}
abstract class ExpectedDeclarationWithBody : KtFirDiagnostic<KtDeclaration>() {
override val diagnosticClass get() = ExpectedDeclarationWithBody::class
}
@@ -2713,6 +2713,20 @@ internal class AbstractPropertyInPrimaryConstructorParametersImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LocalVariableWithTypeParametersWarningImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LocalVariableWithTypeParametersWarning(), KtAbstractFirDiagnostic<KtProperty> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LocalVariableWithTypeParametersImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LocalVariableWithTypeParameters(), KtAbstractFirDiagnostic<KtProperty> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ExpectedDeclarationWithBodyImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,