From 0616e869aa7e7f7f60323878d76accca2b87d4f8 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 2 Sep 2016 21:07:03 +0300 Subject: [PATCH] Quick Fixes: Implement "Remove unused assignment" quickfix #KT-9931 Fixed --- ChangeLog.md | 1 + .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 + .../idea/quickfix/RemoveUnusedValueFix.kt | 93 +++++++++++++++++++ .../removeRedundantAssignment/constant.kt | 5 + .../constant.kt.after | 4 + .../removeRedundantAssignment/functionCall.kt | 7 ++ .../functionCall.kt.after | 7 ++ .../removeRedundantAssignment/notRedundant.kt | 6 ++ .../removeRedundantAssignment/simpleRef.kt | 5 + .../simpleRef.kt.after | 4 + .../changeMutability/funParameter.kt | 1 + .../idea/quickfix/QuickFixTestGenerated.java | 33 +++++++ 12 files changed, 168 insertions(+) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedValueFix.kt create mode 100644 idea/testData/quickfix/removeRedundantAssignment/constant.kt create mode 100644 idea/testData/quickfix/removeRedundantAssignment/constant.kt.after create mode 100644 idea/testData/quickfix/removeRedundantAssignment/functionCall.kt create mode 100644 idea/testData/quickfix/removeRedundantAssignment/functionCall.kt.after create mode 100644 idea/testData/quickfix/removeRedundantAssignment/notRedundant.kt create mode 100644 idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt create mode 100644 idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt.after diff --git a/ChangeLog.md b/ChangeLog.md index 3b1b8c54a18..8bccdbbf004 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -213,6 +213,7 @@ These artifacts include extensions for the types available in the latter JDKs, s ##### New features - [`KT-11525`](https://youtrack.jetbrains.com/issue/KT-11525) Implement "Create type parameter" quickfix +- [`KT-9931`](https://youtrack.jetbrains.com/issue/KT-9931) Implement "Remove unused assignment" quickfix #### Refactorings diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 2971bb73c52..1b12099dd14 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -425,5 +425,7 @@ class QuickFixRegistrar : QuickFixContributor { TYPE_PARAMETER_AS_REIFIED.registerFactory(AddReifiedToTypeParameterOfFunctionFix) TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL.registerFactory(TooLongCharLiteralToStringFix) + + UNUSED_VALUE.registerFactory(RemoveUnusedValueFix) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedValueFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedValueFix.kt new file mode 100644 index 00000000000..332334d2720 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedValueFix.kt @@ -0,0 +1,93 @@ +/* + * 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.daemon.QuickFixBundle +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import org.jetbrains.kotlin.cfg.pseudocode.getContainingPseudocode +import org.jetbrains.kotlin.cfg.pseudocode.sideEffectFree +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode + +class RemoveUnusedValueFix(expression: KtBinaryExpression) : KotlinQuickFixAction(expression) { + enum class RemoveMode { + REMOVE_ALL, KEEP_INITIALIZE, CANCEL + } + + private fun showDialog(variable: KtProperty): RemoveMode { + if (ApplicationManager.getApplication().isUnitTestMode) return RemoveMode.KEEP_INITIALIZE + + val message = + """ + + There are possible side effects found in expressions assigned to the variable '${variable.name}'
+ You can:
+ - Remove the entire assignment, or
+ - Transform assignment right-hand side into the statement on its own.
+ + """ + val exitCode = Messages.showYesNoCancelDialog( + variable.project, + message, + QuickFixBundle.message("side.effects.warning.dialog.title"), + QuickFixBundle.message("side.effect.action.remove"), + QuickFixBundle.message("side.effect.action.transform"), + QuickFixBundle.message("side.effect.action.cancel"), + Messages.getWarningIcon() + ) + return RemoveMode.values()[exitCode] + } + + override fun getFamilyName() = "Remove redundant assignment" + + override fun getText() = familyName + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val lhs = element.left as? KtSimpleNameExpression ?: return + val rhs = element.right ?: return + val variable = lhs.mainReference.resolve() as? KtProperty ?: return + val pseudocode = rhs.getContainingPseudocode(element.analyze(BodyResolveMode.PARTIAL)) + val isSideEffectFree = pseudocode?.getElementValue(rhs)?.createdAt?.sideEffectFree ?: false + var removeMode = RemoveMode.REMOVE_ALL + if (!isSideEffectFree) { + removeMode = showDialog(variable) + } + + when (removeMode) { + RemoveMode.REMOVE_ALL -> element.delete() + RemoveMode.KEEP_INITIALIZE -> element.replace(rhs) + else -> {} + } + } + + companion object : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val expression = Errors.UNUSED_VALUE.cast(diagnostic).psiElement + if (!KtPsiUtil.isAssignment(expression)) return null + if (expression.left !is KtSimpleNameExpression) return null + return RemoveUnusedValueFix(expression) + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeRedundantAssignment/constant.kt b/idea/testData/quickfix/removeRedundantAssignment/constant.kt new file mode 100644 index 00000000000..34b2c270cee --- /dev/null +++ b/idea/testData/quickfix/removeRedundantAssignment/constant.kt @@ -0,0 +1,5 @@ +// "Remove redundant assignment" "true" +fun test() { + var i: Int + i = 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeRedundantAssignment/constant.kt.after b/idea/testData/quickfix/removeRedundantAssignment/constant.kt.after new file mode 100644 index 00000000000..a80df9f2fc1 --- /dev/null +++ b/idea/testData/quickfix/removeRedundantAssignment/constant.kt.after @@ -0,0 +1,4 @@ +// "Remove redundant assignment" "true" +fun test() { + var i: Int +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeRedundantAssignment/functionCall.kt b/idea/testData/quickfix/removeRedundantAssignment/functionCall.kt new file mode 100644 index 00000000000..b910d9ea739 --- /dev/null +++ b/idea/testData/quickfix/removeRedundantAssignment/functionCall.kt @@ -0,0 +1,7 @@ +// "Remove redundant assignment" "true" +fun foo() = 1 + +fun test() { + var i: Int + i = foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeRedundantAssignment/functionCall.kt.after b/idea/testData/quickfix/removeRedundantAssignment/functionCall.kt.after new file mode 100644 index 00000000000..d0569f2238d --- /dev/null +++ b/idea/testData/quickfix/removeRedundantAssignment/functionCall.kt.after @@ -0,0 +1,7 @@ +// "Remove redundant assignment" "true" +fun foo() = 1 + +fun test() { + var i: Int + foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeRedundantAssignment/notRedundant.kt b/idea/testData/quickfix/removeRedundantAssignment/notRedundant.kt new file mode 100644 index 00000000000..5a302b61634 --- /dev/null +++ b/idea/testData/quickfix/removeRedundantAssignment/notRedundant.kt @@ -0,0 +1,6 @@ +// "Remove redundant assignment" "false" +fun foo(): Int { + var i = 1 + i = 2 + return i +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt b/idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt new file mode 100644 index 00000000000..768f372907e --- /dev/null +++ b/idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt @@ -0,0 +1,5 @@ +// "Remove redundant assignment" "true" +fun test(n: Int) { + var i: Int + i = n +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt.after b/idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt.after new file mode 100644 index 00000000000..09dddfe020d --- /dev/null +++ b/idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt.after @@ -0,0 +1,4 @@ +// "Remove redundant assignment" "true" +fun test(n: Int) { + var i: Int +} \ No newline at end of file diff --git a/idea/testData/quickfix/variables/changeMutability/funParameter.kt b/idea/testData/quickfix/variables/changeMutability/funParameter.kt index 7424f192c32..e7500360ba4 100644 --- a/idea/testData/quickfix/variables/changeMutability/funParameter.kt +++ b/idea/testData/quickfix/variables/changeMutability/funParameter.kt @@ -1,4 +1,5 @@ // "Make variable mutable" "false" +// ACTION: Remove redundant assignment // ERROR: Val cannot be reassigned fun fun1(i: Int) { i = 2 diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index aa7e67f527f..f94e028c0e9 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -7166,6 +7166,39 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/removeRedundantAssignment") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RemoveRedundantAssignment extends AbstractQuickFixTest { + public void testAllFilesPresentInRemoveRedundantAssignment() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/removeRedundantAssignment"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("constant.kt") + public void testConstant() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeRedundantAssignment/constant.kt"); + doTest(fileName); + } + + @TestMetadata("functionCall.kt") + public void testFunctionCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeRedundantAssignment/functionCall.kt"); + doTest(fileName); + } + + @TestMetadata("notRedundant.kt") + public void testNotRedundant() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeRedundantAssignment/notRedundant.kt"); + doTest(fileName); + } + + @TestMetadata("simpleRef.kt") + public void testSimpleRef() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeRedundantAssignment/simpleRef.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/removeToStringInStringTemplate") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)