From 580f1d51f6790d5b26d83410184dfda539cbb6b6 Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Wed, 25 Aug 2021 07:22:34 +0000 Subject: [PATCH] FIR checker: report LOCAL_VARIABLE_WITH_TYPE_PARAMETERS --- .../diagnostics/FirDiagnosticsList.kt | 2 + .../fir/analysis/diagnostics/FirErrors.kt | 2 + .../checkers/CommonDeclarationCheckers.kt | 6 +- ...ocalVariableTypeParametersSyntaxChecker.kt | 56 +++++++++++++++++++ .../diagnostics/FirDefaultErrorMessages.kt | 4 ++ ...AnnotationsForPropertyTypeParameter.fir.kt | 2 +- ...ocalVariablesWithTypeParameters_1_3.fir.kt | 14 ++--- ...ocalVariablesWithTypeParameters_1_4.fir.kt | 14 ++--- .../type-parameters/neg/1.fir.kt | 44 +++++++-------- .../diagnostics/KtFirDataClassConverters.kt | 12 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 8 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 14 +++++ 12 files changed, 137 insertions(+), 41 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirLocalVariableTypeParametersSyntaxChecker.kt 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 93dd3ddddc1..e8ff31d49c2 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 @@ -866,6 +866,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { } val ACCESSOR_FOR_DELEGATED_PROPERTY by error() val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error(PositioningStrategy.ABSTRACT_MODIFIER) + val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning(PositioningStrategy.TYPE_PARAMETERS_LIST) + val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error(PositioningStrategy.TYPE_PARAMETERS_LIST) } val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") { 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 222ad75cd7a..c6c67f070fa 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 @@ -476,6 +476,8 @@ object FirErrors { val WRONG_GETTER_RETURN_TYPE by error2() val ACCESSOR_FOR_DELEGATED_PROPERTY by error0() val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0(SourceElementPositioningStrategies.ABSTRACT_MODIFIER) + val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning0(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST) + val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error0(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST) // Multi-platform projects val EXPECTED_DECLARATION_WITH_BODY by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) 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 81f3febe7cb..8d57c405335 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 @@ -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 @@ -59,6 +56,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirDelegatedPropertyChecker, FirInlinePropertyChecker, FirPropertyFromParameterChecker, + FirLocalVariableTypeParametersSyntaxChecker, ) override val classCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirLocalVariableTypeParametersSyntaxChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirLocalVariableTypeParametersSyntaxChecker.kt new file mode 100644 index 00000000000..95828ac9a58 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/syntax/FirLocalVariableTypeParametersSyntaxChecker.kt @@ -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() { + 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) + + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 9b466efbee0..c3055d385a5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -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") diff --git a/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.fir.kt b/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.fir.kt index ce71334dc83..b1898026048 100644 --- a/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.fir.kt @@ -9,6 +9,6 @@ class SomeClass { val <@A1 @A2(3) @A2 @A1(12) @A2("Test") T> T.field: Int get() = 12 fun foo() { - val <@A1 @A2(3) @A2 @A1(12) @A2("Test") T> localVal = 12 + val <@A1 @A2(3) @A2 @A1(12) @A2("Test") T> localVal = 12 } } diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt index c47e5ecf49b..17c60e71162 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.fir.kt @@ -4,13 +4,13 @@ import kotlin.reflect.KProperty fun test() { - val a0 = 0 - val a1 = "" - val a2 = 0 - const val a3 = 0 - lateinit val a4 = 0 - val a5 by Delegate() - val a6 by Delegate<T>() + val a0 = 0 + val a1 = "" + val a2 = 0 + const val a3 = 0 + lateinit val a4 = 0 + val a5 by Delegate() + val a6 by Delegate<T>() } class Delegate { diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt index 61623cf5039..76480ca1c61 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.fir.kt @@ -4,13 +4,13 @@ import kotlin.reflect.KProperty fun test() { - val a0 = 0 - val a1 = "" - val a2 = 0 - const val a3 = 0 - lateinit val a4 = 0 - val a5 by Delegate() - val a6 by Delegate<T>() + val a0 = 0 + val a1 = "" + val a2 = 0 + const val a3 = 0 + lateinit val a4 = 0 + val a5 by Delegate() + val a6 by Delegate<T>() } class Delegate { diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/local-variables/type-parameters/neg/1.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/local-variables/type-parameters/neg/1.fir.kt index 9d99739c652..512368e48d3 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/local-variables/type-parameters/neg/1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/local-variables/type-parameters/neg/1.fir.kt @@ -3,32 +3,32 @@ // TESTCASE NUMBER: 1 fun case_1() { - val x1 = 1 - var x2 = 1 + val x1 = 1 + var x2 = 1 } // TESTCASE NUMBER: 2 fun case_2() { - val x1: Int = 1 - var x2: Int = 1 + val x1: Int = 1 + var x2: Int = 1 } // TESTCASE NUMBER: 3 fun case_3() { - val x1: Map = mapOf(1 to 1) - var x2: Map = mapOf(1 to 1) + val x1: Map = mapOf(1 to 1) + var x2: Map = mapOf(1 to 1) } // TESTCASE NUMBER: 4 fun case_4() { - val y1: Number where __UNRESOLVED__: __UNRESOLVED__ = 1 - var y2: Number where __UNRESOLVED__: __UNRESOLVED__ = 1 + val y1: Number where __UNRESOLVED__: __UNRESOLVED__ = 1 + var y2: Number where __UNRESOLVED__: __UNRESOLVED__ = 1 } // TESTCASE NUMBER: 5 fun case_5() { - val x1: Map = mapOf(1 to 1) - var x2: Map = mapOf(1 to 1) + val x1: Map = mapOf(1 to 1) + var x2: Map = mapOf(1 to 1) } /* @@ -51,19 +51,19 @@ fun case_7() { // TESTCASE NUMBER: 8 fun case_8() { - val x1 = 1 - var x2 = 2 + val x1 = 1 + var x2 = 2 } // TESTCASE NUMBER: 9 -fun case_9(y: Boolean?) = when (val x = y) { +fun case_9(y: Boolean?) = when (val x = y) { true -> null false -> null null -> null } // TESTCASE NUMBER: 10 -fun case_10(x: Boolean?) = when (val x where T: suspend () -> Unit, T: Boolean = x) { +fun case_10(x: Boolean?) = when (val 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 x where T: suspend () -> Unit, T: Boole // TESTCASE NUMBER: 11 fun case_11() { - val x by lazy { 1 } - var x by lazy { 1 } + val x by lazy { 1 } + var x by lazy { 1 } } // TESTCASE NUMBER: 12 fun case_12() { - val x: Int - var x: Int + val x: Int + var x: Int } // TESTCASE NUMBER: 13 fun case_13() { - val x: Int where __UNRESOLVED__: __UNRESOLVED__ - var x: Int where __UNRESOLVED__: __UNRESOLVED__ + val x: Int where __UNRESOLVED__: __UNRESOLVED__ + var x: Int where __UNRESOLVED__: __UNRESOLVED__ } // TESTCASE NUMBER: 14 fun case_14() { - val x1 = 1 - var x2 = 1 + val x1 = 1 + var x2 = 1 } 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 9bb1d781ce4..5bf7a64a3e2 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 @@ -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, 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 fa5ef54b1e1..776d0e8f1e0 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 @@ -1686,6 +1686,14 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = AbstractPropertyInPrimaryConstructorParameters::class } + abstract class LocalVariableWithTypeParametersWarning : KtFirDiagnostic() { + override val diagnosticClass get() = LocalVariableWithTypeParametersWarning::class + } + + abstract class LocalVariableWithTypeParameters : KtFirDiagnostic() { + override val diagnosticClass get() = LocalVariableWithTypeParameters::class + } + abstract class ExpectedDeclarationWithBody : KtFirDiagnostic() { override val diagnosticClass get() = ExpectedDeclarationWithBody::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 2c4bf028d88..da59be53fc4 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 @@ -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 { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class LocalVariableWithTypeParametersImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.LocalVariableWithTypeParameters(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class ExpectedDeclarationWithBodyImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,