diff --git a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java index 94a8a2c2ed54..835dbc292467 100644 --- a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java +++ b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java @@ -9,6 +9,7 @@ import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil; import com.intellij.codeInspection.dataFlow.MethodContract; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; +import com.intellij.psi.impl.source.DummyHolder; import com.intellij.psi.impl.source.tree.JavaSharedImplUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.JavaPsiPatternUtil; @@ -191,24 +192,24 @@ public final class InstanceOfUtils { */ @Nullable public static PsiInstanceOfExpression findCorrespondingInstanceOf(@NotNull PsiTypeCastExpression cast) { - PsiElement context = PsiUtil.skipParenthesizedExprUp(cast.getParent()); + PsiElement context = PsiUtil.skipParenthesizedExprUp(cast.getContext()); if (context instanceof PsiLocalVariable) { - context = context.getParent(); + context = context.getContext(); } else { while (true) { - if (context instanceof PsiPolyadicExpression) { - IElementType tokenType = ((PsiPolyadicExpression)context).getOperationTokenType(); + if (context instanceof PsiPolyadicExpression polyadic) { + IElementType tokenType = polyadic.getOperationTokenType(); if (tokenType.equals(JavaTokenType.ANDAND) || tokenType.equals(JavaTokenType.OROR)) { - PsiInstanceOfExpression instanceOf = findInstanceOf((PsiExpression)context, cast, tokenType.equals(JavaTokenType.ANDAND)); + PsiInstanceOfExpression instanceOf = findInstanceOf(polyadic, cast, tokenType.equals(JavaTokenType.ANDAND)); if (instanceOf != null) { return instanceOf; } } } - if (context instanceof PsiConditionalExpression) { - PsiExpression condition = ((PsiConditionalExpression)context).getCondition(); + if (context instanceof PsiConditionalExpression conditional) { + PsiExpression condition = conditional.getCondition(); if (!PsiTreeUtil.isAncestor(condition, cast, true)) { - boolean whenTrue = PsiTreeUtil.isAncestor(((PsiConditionalExpression)context).getThenExpression(), cast, false); + boolean whenTrue = PsiTreeUtil.isAncestor(conditional.getThenExpression(), cast, false); PsiInstanceOfExpression instanceOf = findInstanceOf(condition, cast, whenTrue); if (instanceOf != null) { return instanceOf; @@ -216,15 +217,17 @@ public final class InstanceOfUtils { } } if ((context instanceof PsiExpression && !(context instanceof PsiLambdaExpression)) || - context instanceof PsiExpressionList || context instanceof PsiLocalVariable) { - context = context.getParent(); + context instanceof PsiExpressionList || context instanceof PsiLocalVariable || + context instanceof DummyHolder) { + context = context.getContext(); continue; } break; } if (!(context instanceof PsiStatement)) return null; } - PsiElement parent = context.getParent(); + if (context == null) return null; + PsiElement parent = context.getContext(); if (parent instanceof PsiCodeBlock) { for (PsiElement stmt = context.getPrevSibling(); stmt != null; stmt = stmt.getPrevSibling()) { if (stmt instanceof PsiIfStatement ifStatement) { @@ -242,7 +245,7 @@ public final class InstanceOfUtils { if (stmt instanceof PsiWhileStatement || stmt instanceof PsiDoWhileStatement || stmt instanceof PsiForStatement) { PsiConditionalLoopStatement loop = (PsiConditionalLoopStatement)stmt; if (PsiTreeUtil.processElements( - loop, e -> !(e instanceof PsiBreakStatement) || ((PsiBreakStatement)e).findExitedStatement() != loop)) { + loop, e -> !(e instanceof PsiBreakStatement breakStatement) || breakStatement.findExitedStatement() != loop)) { PsiInstanceOfExpression instanceOf = findInstanceOf(loop.getCondition(), cast, false); if (instanceOf != null) { return instanceOf; @@ -251,9 +254,9 @@ public final class InstanceOfUtils { } if (stmt instanceof PsiSwitchLabelStatementBase) break; } - if (parent.getParent() instanceof PsiBlockStatement) { - context = parent.getParent(); - parent = context.getParent(); + if (parent.getContext() instanceof PsiBlockStatement) { + context = parent.getContext(); + parent = context.getContext(); } } return processParent(cast, context, parent); @@ -315,7 +318,7 @@ public final class InstanceOfUtils { if (tokenType == JavaTokenType.ANDAND && whenTrue || tokenType == JavaTokenType.OROR && !whenTrue) { for (PsiExpression operand : polyadic.getOperands()) { - if (PsiTreeUtil.isAncestor(operand, cast, false)) return null; + if (PsiTreeUtil.isContextAncestor(operand, cast, false)) return null; PsiInstanceOfExpression result = findInstanceOf(operand, cast, whenTrue); if (result != null) { return result; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java index 208c5334a711..ebf62edeb10e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java @@ -66,7 +66,8 @@ public class SimplifyBooleanExpressionFix extends PsiUpdateModCommandAction PatternResolveState.fromBoolean(mySubExpressionValue) - .equals(PatternResolveState.stateAtParent(var, subExpression))); + .equals(PatternResolveState.stateAtParent(var, subExpression)) && + newTargetForPatternVariable(subExpression, var) == null); } private boolean canExtractSideEffect(PsiExpression subExpression) { @@ -127,6 +128,20 @@ public class SimplifyBooleanExpressionFix extends PsiUpdateModCommandAction isBreakOrContinue(e, doWhileLoop)).iterator().hasNext(); } @@ -157,6 +172,7 @@ public class SimplifyBooleanExpressionFix extends PsiUpdateModCommandAction variables = JavaPsiPatternUtil.getExposedPatternVariables(subExpression); + for (PsiPatternVariable variable : variables) { + if (VariableAccessUtils.variableIsUsed(variable, variable.getDeclarationScope())) { + PsiInstanceOfExpression target = newTargetForPatternVariable(subExpression, variable); + if (target != null) { + PsiInstanceOfExpression updated = (PsiInstanceOfExpression)JavaPsiFacade.getElementFactory(subExpression.getProject()) + .createExpressionFromText("x instanceof T t", target); + updated.getOperand().replace(target.getOperand()); + PsiTypeTestPattern newPattern = (PsiTypeTestPattern)Objects.requireNonNull(updated.getPattern()); + PsiTypeElement checkType = target.getCheckType(); + if (checkType == null) continue; + Objects.requireNonNull(newPattern.getCheckType()).replace(checkType); + Objects.requireNonNull(newPattern.getPatternVariable()).replace(variable); + target.replace(updated); + variable.delete(); + } + } + } + } + private PsiExpression ensureCodeBlock(@NotNull Project project, PsiExpression subExpression) { if (!mySubExpressionValue) { // Prevent extracting while condition to internal 'if' diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/afterPatternRetarget.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/afterPatternRetarget.java new file mode 100644 index 000000000000..1ef065105b12 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/afterPatternRetarget.java @@ -0,0 +1,8 @@ +// "Simplify 'obj instanceof String str' to true" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof String str) || str.isEmpty()) { + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/afterPatternRetarget2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/afterPatternRetarget2.java new file mode 100644 index 000000000000..07d4f773c8e8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/afterPatternRetarget2.java @@ -0,0 +1,10 @@ +// "Simplify 'obj instanceof String str' to true" "true" +class Test { + void test(Object obj) { + if (obj instanceof String str) { + if (str.isEmpty()) { + + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/beforePatternRetarget.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/beforePatternRetarget.java new file mode 100644 index 000000000000..3adafb8b25b8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/beforePatternRetarget.java @@ -0,0 +1,8 @@ +// "Simplify 'obj instanceof String str' to true" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof String) || obj instanceof String str && str.isEmpty()) { + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/beforePatternRetarget2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/beforePatternRetarget2.java new file mode 100644 index 000000000000..2632052be4f4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unwrapIfStatement/beforePatternRetarget2.java @@ -0,0 +1,10 @@ +// "Simplify 'obj instanceof String str' to true" "true" +class Test { + void test(Object obj) { + if (obj instanceof String) { + if (obj instanceof String str && str.isEmpty()) { + + } + } + } +} \ No newline at end of file