Quick Fixes: Implement "Remove unused assignment" quickfix

#KT-9931 Fixed
This commit is contained in:
Alexey Sedunov
2016-09-02 21:07:03 +03:00
parent 074ad6b5f0
commit 0616e869aa
12 changed files with 168 additions and 0 deletions
+1
View File
@@ -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
@@ -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)
}
}
@@ -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<KtBinaryExpression>(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 =
"""<html>
<body>
There are possible side effects found in expressions assigned to the variable '${variable.name}'<br>
You can:<br>
-&nbsp;<b>Remove</b> the entire assignment, or<br>
-&nbsp;<b>Transform</b> assignment right-hand side into the statement on its own.<br>
</body>
</html>"""
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)
}
}
}
@@ -0,0 +1,5 @@
// "Remove redundant assignment" "true"
fun test() {
var i: Int
<caret>i = 1
}
@@ -0,0 +1,4 @@
// "Remove redundant assignment" "true"
fun test() {
var i: Int
<caret>}
@@ -0,0 +1,7 @@
// "Remove redundant assignment" "true"
fun foo() = 1
fun test() {
var i: Int
<caret>i = foo()
}
@@ -0,0 +1,7 @@
// "Remove redundant assignment" "true"
fun foo() = 1
fun test() {
var i: Int
<caret>foo()
}
@@ -0,0 +1,6 @@
// "Remove redundant assignment" "false"
fun foo(): Int {
var i = 1
<caret>i = 2
return i
}
@@ -0,0 +1,5 @@
// "Remove redundant assignment" "true"
fun test(n: Int) {
var i: Int
<caret>i = n
}
@@ -0,0 +1,4 @@
// "Remove redundant assignment" "true"
fun test(n: Int) {
var i: Int
<caret>}
@@ -1,4 +1,5 @@
// "Make variable mutable" "false"
// ACTION: Remove redundant assignment
// ERROR: Val cannot be reassigned
fun fun1(i: Int) {
<caret>i = 2
@@ -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)