From 958aeff94b0c6c31178e6e69ac820bd1897bfb47 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 24 Dec 2018 01:30:17 +0300 Subject: [PATCH] Prohibit type parameters for local variables in LV >= 1.4 & -progressive #KT-8341 Fixed --- .../jetbrains/kotlin/diagnostics/Errors.java | 2 ++ .../rendering/DefaultErrorMessages.java | 2 ++ .../resolve/PlatformConfiguratorBase.kt | 3 +- .../LocalVariableTypeParametersChecker.kt | 31 +++++++++++++++++++ .../AnnotationsForPropertyTypeParameter.kt | 2 +- .../localVariablesWithTypeParameters_1_3.kt | 19 ++++++++++++ .../localVariablesWithTypeParameters_1_3.txt | 12 +++++++ .../localVariablesWithTypeParameters_1_4.kt | 19 ++++++++++++ .../localVariablesWithTypeParameters_1_4.txt | 12 +++++++ .../checkers/DiagnosticsTestGenerated.java | 10 ++++++ .../DiagnosticsUsingJavacTestGenerated.java | 10 ++++++ .../kotlin/config/LanguageVersionSettings.kt | 1 + .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 3 ++ .../quickfix/RemovePsiElementSimpleFix.kt | 7 +++++ .../removeTypeParametersFromLocalVariable.kt | 5 +++ ...veTypeParametersFromLocalVariable.kt.after | 5 +++ .../QuickFixMultiFileTestGenerated.java | 13 ++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 18 +++++++++++ 18 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/LocalVariableTypeParametersChecker.kt create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.kt create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.txt create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.txt create mode 100644 idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt create mode 100644 idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index e42e8421555..3da1965289a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -954,6 +954,8 @@ public interface Errors { DiagnosticFactory0 LOCAL_EXTENSION_PROPERTY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 LOCAL_VARIABLE_WITH_GETTER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 LOCAL_VARIABLE_WITH_SETTER = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING = DiagnosticFactory0.create(WARNING); + DiagnosticFactory0 LOCAL_VARIABLE_WITH_TYPE_PARAMETERS = DiagnosticFactory0.create(ERROR); DiagnosticFactory3 INVISIBLE_SETTER = DiagnosticFactory3.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index cdb408ffdb4..8d981838323 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -399,6 +399,8 @@ public class DefaultErrorMessages { MAP.put(LOCAL_EXTENSION_PROPERTY, "Local extension properties are not allowed"); MAP.put(LOCAL_VARIABLE_WITH_GETTER, "Local variables are not allowed to have getters"); MAP.put(LOCAL_VARIABLE_WITH_SETTER, "Local variables are not allowed to have setters"); + 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(VAL_WITH_SETTER, "A 'val'-property cannot have a setter"); MAP.put(DEPRECATED_IDENTITY_EQUALS, "Identity equality for arguments of types {0} and {1} is deprecated", RENDER_TYPE, RENDER_TYPE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index 9ce8c7b927e..456c2e52aff 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -33,7 +33,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( PropertiesWithBackingFieldsInsideInlineClass(), AnnotationClassTargetAndRetentionChecker(), ReservedMembersAndConstructsForInlineClass(), - ResultClassInReturnTypeChecker() + ResultClassInReturnTypeChecker(), + LocalVariableTypeParametersChecker() ) private val DEFAULT_CALL_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/LocalVariableTypeParametersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/LocalVariableTypeParametersChecker.kt new file mode 100644 index 00000000000..9d1fc1909f9 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/LocalVariableTypeParametersChecker.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.resolve.checkers + +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtProperty + +class LocalVariableTypeParametersChecker : DeclarationChecker { + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (declaration !is KtProperty || descriptor !is LocalVariableDescriptor) return + + val typeParameters = declaration.typeParameters + val typeParametersList = declaration.typeParameterList + if (typeParameters.isEmpty() || typeParametersList == null) return + + val diagnostic = + if (context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitTypeParametersForLocalVariables)) + Errors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS + else + Errors.LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING + + context.trace.report(diagnostic.on(typeParametersList)) + } +} diff --git a/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.kt b/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.kt index ac6e1774733..8e0b675731c 100644 --- a/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.kt +++ b/compiler/testData/diagnostics/tests/annotations/AnnotationsForPropertyTypeParameter.kt @@ -7,6 +7,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 } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.kt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.kt new file mode 100644 index 00000000000..8271d9891b3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.kt @@ -0,0 +1,19 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !LANGUAGE: -ProhibitTypeParametersForLocalVariables + +import kotlin.reflect.KProperty + +fun test() { + val a0 = 0 + val __UNRESOLVED__> a1 = "" + val String> a2 = 0 + const val a3 = 0 + lateinit val a4 = 0 + val a5 by Delegate() + val a6 by Delegate<T>() +} + +class Delegate { + operator fun getValue(thisRef: Any?, property: KProperty<*>): String = "" + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.txt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.txt new file mode 100644 index 00000000000..f21ebe626c0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.txt @@ -0,0 +1,12 @@ +package + +public fun test(): kotlin.Unit + +public final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final operator fun setValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>, /*2*/ value: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt new file mode 100644 index 00000000000..80ecdeade12 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt @@ -0,0 +1,19 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !LANGUAGE: +ProhibitTypeParametersForLocalVariables + +import kotlin.reflect.KProperty + +fun test() { + val a0 = 0 + val __UNRESOLVED__> a1 = "" + val String> a2 = 0 + const val a3 = 0 + lateinit val a4 = 0 + val a5 by Delegate() + val a6 by Delegate<T>() +} + +class Delegate { + operator fun getValue(thisRef: Any?, property: KProperty<*>): String = "" + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.txt b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.txt new file mode 100644 index 00000000000..f21ebe626c0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.txt @@ -0,0 +1,12 @@ +package + +public fun test(): kotlin.Unit + +public final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final operator fun setValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>, /*2*/ value: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 7ec55f41c0a..9f8a8471d3e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -5133,6 +5133,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/declarationChecks/LocalVariableWithNoTypeInformation.kt"); } + @TestMetadata("localVariablesWithTypeParameters_1_3.kt") + public void testLocalVariablesWithTypeParameters_1_3() throws Exception { + runTest("compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.kt"); + } + + @TestMetadata("localVariablesWithTypeParameters_1_4.kt") + public void testLocalVariablesWithTypeParameters_1_4() throws Exception { + runTest("compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt"); + } + @TestMetadata("mulitpleVarargParameters.kt") public void testMulitpleVarargParameters() throws Exception { runTest("compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index d8e8fb8ade1..44024ff3e1d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -5133,6 +5133,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/declarationChecks/LocalVariableWithNoTypeInformation.kt"); } + @TestMetadata("localVariablesWithTypeParameters_1_3.kt") + public void testLocalVariablesWithTypeParameters_1_3() throws Exception { + runTest("compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_3.kt"); + } + + @TestMetadata("localVariablesWithTypeParameters_1_4.kt") + public void testLocalVariablesWithTypeParameters_1_4() throws Exception { + runTest("compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt"); + } + @TestMetadata("mulitpleVarargParameters.kt") public void testMulitpleVarargParameters() throws Exception { runTest("compiler/testData/diagnostics/tests/declarationChecks/mulitpleVarargParameters.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index d6f2af6ac57..5eade519c99 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -94,6 +94,7 @@ enum class LanguageFeature( WarningOnMainUnusedParameter(KOTLIN_1_4), PolymorphicSignature(KOTLIN_1_4), ProhibitConcurrentHashMapContains(KOTLIN_1_4, kind = BUG_FIX), + ProhibitTypeParametersForLocalVariables(KOTLIN_1_4, kind = BUG_FIX), ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX), // Temporarily disabled, see KT-27084/KT-22379 diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 93bf7a0653c..46eb09c964b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -271,6 +271,9 @@ class QuickFixRegistrar : QuickFixContributor { TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER.registerFactory(RemovePsiElementSimpleFix.RemoveTypeArgumentsFactory) + LOCAL_VARIABLE_WITH_TYPE_PARAMETERS.registerFactory(RemovePsiElementSimpleFix.RemoveTypeParametersFactory) + LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING.registerFactory(RemovePsiElementSimpleFix.RemoveTypeParametersFactory) + UNCHECKED_CAST.registerFactory(ChangeToStarProjectionFix) CANNOT_CHECK_FOR_ERASED.registerFactory(ChangeToStarProjectionFix) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt index 3e61dc7d6f1..97387eaf170 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt @@ -58,6 +58,13 @@ open class RemovePsiElementSimpleFix(element: PsiElement, private val text: Stri } } + object RemoveTypeParametersFactory : KotlinSingleIntentionActionFactory() { + public override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + val element = diagnostic.psiElement.getNonStrictParentOfType() ?: return null + return RemovePsiElementSimpleFix(element, "Remove type parameters") + } + } + object RemoveVariableFactory : KotlinSingleIntentionActionFactory() { public override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { val expression = diagnostic.psiElement.getNonStrictParentOfType() ?: return null diff --git a/idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt b/idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt new file mode 100644 index 00000000000..61fccba7ed7 --- /dev/null +++ b/idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt @@ -0,0 +1,5 @@ +// "Remove type parameters" "true" + +fun test() { + val x = 0 +} \ No newline at end of file diff --git a/idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt.after b/idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt.after new file mode 100644 index 00000000000..edca5085d6b --- /dev/null +++ b/idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt.after @@ -0,0 +1,5 @@ +// "Remove type parameters" "true" + +fun test() { + val x = 0 +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index a51670344f1..91de120b155 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -2840,6 +2840,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/localVariableWithTypeParameters") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalVariableWithTypeParameters extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInLocalVariableWithTypeParameters() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/localVariableWithTypeParameters"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + @TestMetadata("idea/testData/quickfix/makeConstructorParameterProperty") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 78112d92f77..b497b0b033e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -7415,6 +7415,24 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/localVariableWithTypeParameters") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalVariableWithTypeParameters extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInLocalVariableWithTypeParameters() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/localVariableWithTypeParameters"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("removeTypeParametersFromLocalVariable.kt") + public void testRemoveTypeParametersFromLocalVariable() throws Exception { + runTest("idea/testData/quickfix/localVariableWithTypeParameters/removeTypeParametersFromLocalVariable.kt"); + } + } + @TestMetadata("idea/testData/quickfix/makeConstructorParameterProperty") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)