RemoveUnusedVariableUtil: code generation fixes

1. Support Java 12 switch rules and switch expressions (IDEA-203692)
2. Support void expression lambdas
3. Fix PSI structure when expression list statement is reduced to single expression
This commit is contained in:
Tagir Valeev
2018-12-20 13:49:11 +07:00
parent aaa8b07b1b
commit 04f7352faa
10 changed files with 96 additions and 20 deletions

View File

@@ -59,10 +59,9 @@ public class RemoveUnusedVariableUtil {
PsiElement element) throws IncorrectOperationException {
PsiElement elementToReplace = element;
PsiElement expressionToReplaceWith = expression;
if (element.getParent() instanceof PsiExpressionStatement) {
if (element.getParent() instanceof PsiExpressionStatement || element.getParent() instanceof PsiExpressionListStatement) {
elementToReplace = element.getParent();
expressionToReplaceWith =
factory.createStatementFromText((expression == null ? "" : expression.getText()) + ";", null);
expressionToReplaceWith = factory.createStatementFromText((expression == null ? "" : expression.getText()) + ";", null);
if (isForLoopUpdate(elementToReplace)) {
PsiElement lastChild = expressionToReplaceWith.getLastChild();
if (PsiUtil.isJavaToken(lastChild, JavaTokenType.SEMICOLON)) {
@@ -71,8 +70,7 @@ public class RemoveUnusedVariableUtil {
}
}
else if (element.getParent() instanceof PsiDeclarationStatement) {
expressionToReplaceWith =
factory.createStatementFromText((expression == null ? "" : expression.getText()) + ";", null);
expressionToReplaceWith = factory.createStatementFromText((expression == null ? "" : expression.getText()) + ";", null);
}
return elementToReplace.replace(expressionToReplaceWith);
}
@@ -81,18 +79,26 @@ public class RemoveUnusedVariableUtil {
PsiElementFactory factory,
PsiElement element) throws IncorrectOperationException {
// if element used in expression, subexpression will do
if (!(element.getParent() instanceof PsiExpressionStatement) &&
!(element.getParent() instanceof PsiDeclarationStatement)) {
PsiElement parent = element.getParent();
if (!(parent instanceof PsiExpressionStatement) && !(parent instanceof PsiDeclarationStatement)) {
return expression;
}
return factory.createStatementFromText((expression == null ? "" : expression.getText()) + ";", null);
String replacement;
if (expression == null) {
boolean needBlock = parent instanceof PsiExpressionStatement && parent.getParent() instanceof PsiSwitchLabeledRuleStatement;
replacement = needBlock ? "{}" : ";";
}
else {
replacement = expression.getText() + ";";
}
return factory.createStatementFromText(replacement, null);
}
static void deleteWholeStatement(PsiElement element, PsiElementFactory factory)
throws IncorrectOperationException {
// just delete it altogether
if (element.getParent() instanceof PsiExpressionStatement) {
PsiExpressionStatement parent = (PsiExpressionStatement)element.getParent();
PsiElement parent = element.getParent();
if (parent instanceof PsiExpressionStatement) {
if (parent.getParent() instanceof PsiCodeBlock || isForLoopUpdate(parent)) {
parent.delete();
}
@@ -101,6 +107,20 @@ public class RemoveUnusedVariableUtil {
parent.replace(createStatementIfNeeded(null, factory, element));
}
}
else if (parent instanceof PsiExpressionList && parent.getParent() instanceof PsiExpressionListStatement) {
PsiExpressionList list = (PsiExpressionList)parent;
PsiExpression[] expressions = list.getExpressions();
if (expressions.length == 2) {
PsiExpression other = expressions[0] == element ? expressions[1] : expressions[0];
replaceElementWithExpression(other, factory, parent);
}
else {
element.delete();
}
}
else if (element.getParent() instanceof PsiLambdaExpression) {
element.replace(factory.createCodeBlock());
}
else {
element.delete();
}
@@ -144,9 +164,9 @@ public class RemoveUnusedVariableUtil {
if (rExpression == null) return true;
// replace assignment with expression and resimplify
boolean sideEffectFound = checkSideEffects(rExpression, variable, sideEffects);
if (!isStatementExpression(expression) || PsiUtil.isStatement(rExpression)) {
if (!ExpressionUtils.isVoidContext(expression) || PsiUtil.isStatement(rExpression)) {
if (deleteMode == RemoveMode.MAKE_STATEMENT ||
deleteMode == RemoveMode.DELETE_ALL && !(element.getParent() instanceof PsiExpressionStatement)) {
deleteMode == RemoveMode.DELETE_ALL && !ExpressionUtils.isVoidContext(expression)) {
element = replaceElementWithExpression(rExpression, factory, element);
element = eraseUnnecessaryOuterParentheses(element);
List<PsiElement> references = new ArrayList<>();
@@ -229,10 +249,4 @@ public class RemoveUnusedVariableUtil {
return parent instanceof PsiForStatement &&
((PsiForStatement)parent).getUpdate() == element;
}
private static boolean isStatementExpression(PsiExpression expression) {
PsiElement parent = expression.getParent();
return parent instanceof PsiExpressionStatement ||
parent instanceof PsiExpressionList && parent.getParent() instanceof PsiExpressionListStatement;
}
}

View File

@@ -0,0 +1,6 @@
// "Remove variable 'i'" "true"
public class Main {
void test(String s) {
foo(1);
}
}

View File

@@ -0,0 +1,8 @@
// "Remove field 'x'" "true"
public class Main {
void test() {
Runnable r = () -> {
};
}
}

View File

@@ -0,0 +1,8 @@
// "Remove variable 'i'" "true"
public class Main {
int test(String s) {
return switch(s) {
default -> 1;
}
}
}

View File

@@ -0,0 +1,9 @@
// "Remove variable 'i'" "true"
public class Main {
void test(String s) {
switch(s) {
case "foo" -> {
}
}
}
}

View File

@@ -0,0 +1,7 @@
// "Remove variable 'i'" "true"
public class Main {
void test(String s) {
int <caret>i;
foo(i = 1);
}
}

View File

@@ -0,0 +1,8 @@
// "Remove field 'x'" "true"
public class Main {
private int <caret>x;
void test() {
Runnable r = () -> x = 1;
}
}

View File

@@ -0,0 +1,9 @@
// "Remove variable 'i'" "true"
public class Main {
int test(String s) {
int <caret>i;
return switch(s) {
default -> i = 1;
}
}
}

View File

@@ -0,0 +1,9 @@
// "Remove variable 'i'" "true"
public class Main {
void test(String s) {
int <caret>i;
switch(s) {
case "foo" -> i = 1;
}
}
}

View File

@@ -17,14 +17,12 @@ package com.intellij.java.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
import com.intellij.testFramework.PsiTestUtil;
public class RemoveUnusedVariableTest extends LightQuickFixParameterizedTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
enableInspectionTool(new UnusedDeclarationInspection());
PsiTestUtil.disablePsiTextConsistencyChecks(getTestRootDisposable());
}
@Override