From edacc7f8d720e6e3cea12d9e2d02d7d5f69912a2 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 9 Sep 2016 18:13:16 +0300 Subject: [PATCH] Quick-fix for reassignment in try / catch (fold to assignment) #KT-13778 Fixed --- .../quickfix/LiftAssignmentOutOfTryFix.kt | 61 +++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 1 + .../quickfix/foldTryCatch/conditional.kt | 16 +++++ .../quickfix/foldTryCatch/emptyFinally.kt | 13 ++++ .../foldTryCatch/emptyFinally.kt.after | 11 ++++ .../foldTryCatch/multipleExceptions.kt | 18 ++++++ .../foldTryCatch/multipleExceptions.kt.after | 15 +++++ idea/testData/quickfix/foldTryCatch/shadow.kt | 16 +++++ idea/testData/quickfix/foldTryCatch/simple.kt | 12 ++++ .../quickfix/foldTryCatch/simple.kt.after | 11 ++++ .../idea/quickfix/QuickFixTestGenerated.java | 39 ++++++++++++ 11 files changed, 213 insertions(+) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/LiftAssignmentOutOfTryFix.kt create mode 100644 idea/testData/quickfix/foldTryCatch/conditional.kt create mode 100644 idea/testData/quickfix/foldTryCatch/emptyFinally.kt create mode 100644 idea/testData/quickfix/foldTryCatch/emptyFinally.kt.after create mode 100644 idea/testData/quickfix/foldTryCatch/multipleExceptions.kt create mode 100644 idea/testData/quickfix/foldTryCatch/multipleExceptions.kt.after create mode 100644 idea/testData/quickfix/foldTryCatch/shadow.kt create mode 100644 idea/testData/quickfix/foldTryCatch/simple.kt create mode 100644 idea/testData/quickfix/foldTryCatch/simple.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/LiftAssignmentOutOfTryFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/LiftAssignmentOutOfTryFix.kt new file mode 100644 index 00000000000..f6d99ae5896 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/LiftAssignmentOutOfTryFix.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.intentions.branchedTransformations.BranchedFoldingUtils +import org.jetbrains.kotlin.psi.* + +class LiftAssignmentOutOfTryFix(element: KtTryExpression): KotlinQuickFixAction(element) { + override fun getFamilyName() = text + + override fun getText() = "Lift assignment out of 'try' expression" + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val tryAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.tryBlock) ?: return + + val op = tryAssignment.operationReference.text + val leftText = tryAssignment.left?.text ?: return + + tryAssignment.replace(tryAssignment.right ?: return) + + for (catchClause in element.catchClauses) { + val catchAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(catchClause.catchBody) + catchAssignment?.replace(catchAssignment.right!!) + } + + element.replace(KtPsiFactory(element).createExpressionByPattern("$0 $1 $2", leftText, op, element)) + } + + companion object : KotlinSingleIntentionActionFactory() { + + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val expression = diagnostic.psiElement as? KtExpression ?: return null + val originalCatch = expression.parent?.parent?.parent as? KtCatchClause ?: return null + val tryExpression = originalCatch.parent as? KtTryExpression ?: return null + val tryAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(tryExpression.tryBlock) ?: return null + for (catchClause in tryExpression.catchClauses) { + val catchAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(catchClause.catchBody) ?: return null + if (!BranchedFoldingUtils.checkAssignmentsMatch(tryAssignment, catchAssignment)) return null + } + return LiftAssignmentOutOfTryFix(tryExpression) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 7181f84e036..363725ac68a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -176,6 +176,7 @@ class QuickFixRegistrar : QuickFixContributor { VAL_WITH_SETTER.registerFactory(ChangeVariableMutabilityFix.VAL_WITH_SETTER_FACTORY) VAL_REASSIGNMENT.registerFactory(ChangeVariableMutabilityFix.VAL_REASSIGNMENT_FACTORY) + VAL_REASSIGNMENT.registerFactory(LiftAssignmentOutOfTryFix) CAPTURED_VAL_INITIALIZATION.registerFactory(ChangeVariableMutabilityFix.CAPTURED_VAL_INITIALIZATION_FACTORY) VAR_OVERRIDDEN_BY_VAL.registerFactory(ChangeVariableMutabilityFix.VAR_OVERRIDDEN_BY_VAL_FACTORY) VAR_ANNOTATION_PARAMETER.registerFactory(ChangeVariableMutabilityFix.VAR_ANNOTATION_PARAMETER_FACTORY) diff --git a/idea/testData/quickfix/foldTryCatch/conditional.kt b/idea/testData/quickfix/foldTryCatch/conditional.kt new file mode 100644 index 00000000000..821894e9357 --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/conditional.kt @@ -0,0 +1,16 @@ +// "Lift assignment out of 'try' expression" "false" +// ACTION: Make variable mutable +// ERROR: Val cannot be reassigned +// WITH_RUNTIME + +fun foo(arg: Boolean) { + val x: Int + try { + if (arg) { + x = 1 + } + } + catch (e: Exception) { + x = 2 + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/foldTryCatch/emptyFinally.kt b/idea/testData/quickfix/foldTryCatch/emptyFinally.kt new file mode 100644 index 00000000000..ea929579f0f --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/emptyFinally.kt @@ -0,0 +1,13 @@ +// "Lift assignment out of 'try' expression" "true" +// WITH_RUNTIME + +fun foo() { + val x: Int + try { + x = 1 + } + catch (e: Exception) { + x = 2 + } + finally {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/foldTryCatch/emptyFinally.kt.after b/idea/testData/quickfix/foldTryCatch/emptyFinally.kt.after new file mode 100644 index 00000000000..cf8b45180eb --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/emptyFinally.kt.after @@ -0,0 +1,11 @@ +// "Lift assignment out of 'try' expression" "true" +// WITH_RUNTIME + +fun foo() { + val x: Int + x = try { + 1 + } catch (e: Exception) { + 2 + } finally {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/foldTryCatch/multipleExceptions.kt b/idea/testData/quickfix/foldTryCatch/multipleExceptions.kt new file mode 100644 index 00000000000..49c559aa4a1 --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/multipleExceptions.kt @@ -0,0 +1,18 @@ +// "Lift assignment out of 'try' expression" "true" +// WITH_RUNTIME + +fun foo() { + val x: Int + try { + x = 1 + } + catch (e: RuntimeException) { + x = 2 + } + catch (e: Exception) { + x = 3 + } + catch (e: Throwable) { + x = 4 + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/foldTryCatch/multipleExceptions.kt.after b/idea/testData/quickfix/foldTryCatch/multipleExceptions.kt.after new file mode 100644 index 00000000000..94f4f61b8ec --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/multipleExceptions.kt.after @@ -0,0 +1,15 @@ +// "Lift assignment out of 'try' expression" "true" +// WITH_RUNTIME + +fun foo() { + val x: Int + x = try { + 1 + } catch (e: RuntimeException) { + 2 + } catch (e: Exception) { + 3 + } catch (e: Throwable) { + 4 + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/foldTryCatch/shadow.kt b/idea/testData/quickfix/foldTryCatch/shadow.kt new file mode 100644 index 00000000000..54c7ffe86da --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/shadow.kt @@ -0,0 +1,16 @@ +// "Lift assignment out of 'try' expression" "false" +// ACTION: Make variable mutable +// ERROR: Val cannot be reassigned +// ERROR: Val cannot be reassigned +// WITH_RUNTIME + +fun foo() { + val x = 1 + try { + val x = 2 + x = 3 + } + catch(e: Exception) { + x = 4 + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/foldTryCatch/simple.kt b/idea/testData/quickfix/foldTryCatch/simple.kt new file mode 100644 index 00000000000..f3c675a0e1d --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/simple.kt @@ -0,0 +1,12 @@ +// "Lift assignment out of 'try' expression" "true" +// WITH_RUNTIME + +fun foo() { + val x: Int + try { + x = 1 + } + catch (e: Exception) { + x = 2 + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/foldTryCatch/simple.kt.after b/idea/testData/quickfix/foldTryCatch/simple.kt.after new file mode 100644 index 00000000000..3ea7f86cee6 --- /dev/null +++ b/idea/testData/quickfix/foldTryCatch/simple.kt.after @@ -0,0 +1,11 @@ +// "Lift assignment out of 'try' expression" "true" +// WITH_RUNTIME + +fun foo() { + val x: Int + x = try { + 1 + } catch (e: Exception) { + 2 + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 58aa7b9aa44..b2f40dcf9aa 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -5122,6 +5122,45 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/foldTryCatch") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class FoldTryCatch extends AbstractQuickFixTest { + public void testAllFilesPresentInFoldTryCatch() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/foldTryCatch"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("conditional.kt") + public void testConditional() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/foldTryCatch/conditional.kt"); + doTest(fileName); + } + + @TestMetadata("emptyFinally.kt") + public void testEmptyFinally() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/foldTryCatch/emptyFinally.kt"); + doTest(fileName); + } + + @TestMetadata("multipleExceptions.kt") + public void testMultipleExceptions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/foldTryCatch/multipleExceptions.kt"); + doTest(fileName); + } + + @TestMetadata("shadow.kt") + public void testShadow() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/foldTryCatch/shadow.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/foldTryCatch/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/implement") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)