diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPatternVariable.java b/java/java-psi-api/src/com/intellij/psi/PsiPatternVariable.java index 05733358f94d..0a3d432ee032 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiPatternVariable.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiPatternVariable.java @@ -8,6 +8,10 @@ import org.jetbrains.annotations.Nullable; * A variable declared within the pattern */ public interface PsiPatternVariable extends PsiVariable { + @NotNull + @Override + String getName(); + @NotNull @Override PsiTypeElement getTypeElement(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCodeBlockImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCodeBlockImpl.java index 01930c35426c..ef76d94f7f1d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCodeBlockImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCodeBlockImpl.java @@ -239,15 +239,42 @@ public class PsiCodeBlockImpl extends LazyParseablePsiElement implements PsiCode final ElementClassHint elementClassHint = processor.getHint(ElementClassHint.KEY); final String name = hint.getName(state); if ((elementClassHint == null || elementClassHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) && classesSet.contains(name)) { - return PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place); + return walkChildren(processor, state, lastParent, place); } if ((elementClassHint == null || elementClassHint.shouldProcess(ElementClassHint.DeclarationKind.VARIABLE)) && variablesSet.contains(name)) { - return PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place); + return walkChildren(processor, state, lastParent, place); } } else { + return walkChildren(processor, state, lastParent, place); + } + return true; + } + + private boolean walkChildren(@NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement lastParent, + @NotNull PsiElement place) { + if (!(getParent() instanceof PsiSwitchBlock)) { return PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place); } + PsiElement child = null; + if (lastParent != null && lastParent.getParent() == this) { + child = lastParent.getPrevSibling(); + if (child == null) return true; // first element + } + + if (child == null) { + child = ((PsiElement)this).getLastChild(); + } + + while (child != null) { + if (child instanceof PsiSwitchLabelStatementBase) { + state = PatternResolveState.WHEN_NONE.putInto(state); + } + if (!child.processDeclarations(processor, state, null, place)) return false; + child = child.getPrevSibling(); + } return true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java index 5cfceec28cbf..36a39fb5aa18 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java @@ -197,6 +197,7 @@ public class PsiConditionalExpressionImpl extends ExpressionPsiElement implement @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { + if (lastParent == null) return true; ElementClassHint elementClassHint = processor.getHint(ElementClassHint.KEY); if (elementClassHint != null && !elementClassHint.shouldProcess(ElementClassHint.DeclarationKind.VARIABLE)) return true; PsiExpression condition = getCondition(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiIfStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiIfStatementImpl.java index ff1ebcf03913..382b98c7bd60 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiIfStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiIfStatementImpl.java @@ -26,6 +26,7 @@ import com.intellij.psi.impl.source.tree.CompositePsiElement; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.scope.ElementClassHint; +import com.intellij.psi.scope.NameHint; import com.intellij.psi.scope.PatternResolveState; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.ChildRoleBase; @@ -209,6 +210,7 @@ public class PsiIfStatementImpl extends CompositePsiElement implements PsiIfStat PsiStatement thenBranch = getThenBranch(); PsiStatement elseBranch = getElseBranch(); if (lastParent == null) { + if (state.get(PatternResolveState.KEY) == PatternResolveState.WHEN_NONE) return true; PsiScopeProcessor conditionProcessor; if (state.get(PatternResolveState.KEY) == PatternResolveState.WHEN_BOTH) { conditionProcessor = processor; @@ -216,6 +218,10 @@ public class PsiIfStatementImpl extends CompositePsiElement implements PsiIfStat else { conditionProcessor = (element, s) -> { LOG.assertTrue(element instanceof PsiPatternVariable); + final NameHint hint = processor.getHint(NameHint.KEY); + if (hint != null && !((PsiPatternVariable)element).getName().equals(hint.getName(s))) { + return true; + } ControlFlow flow; try { flow = ControlFlowFactory.getInstance(getProject()).getControlFlow( diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiWhileStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiWhileStatementImpl.java index a630a7422e35..3666f50a9562 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiWhileStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiWhileStatementImpl.java @@ -22,6 +22,7 @@ import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.Constants; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.scope.ElementClassHint; +import com.intellij.psi.scope.NameHint; import com.intellij.psi.scope.PatternResolveState; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.ChildRoleBase; @@ -137,10 +138,15 @@ public class PsiWhileStatementImpl extends PsiLoopStatementImpl implements PsiWh @NotNull ResolveState state, @NotNull PsiElement place, @NotNull PsiConditionalLoopStatement loop) { + if (state.get(PatternResolveState.KEY) == PatternResolveState.WHEN_NONE) return true; PsiExpression condition = loop.getCondition(); if (condition == null) return true; PsiScopeProcessor conditionProcessor = (element, s) -> { assert element instanceof PsiPatternVariable; + final NameHint hint = processor.getHint(NameHint.KEY); + if (hint != null && !((PsiPatternVariable)element).getName().equals(hint.getName(s))) { + return true; + } PatternResolveState resolveState = PatternResolveState.stateAtParent((PsiPatternVariable)element, condition); if (resolveState == PatternResolveState.WHEN_TRUE || !PsiTreeUtil diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/PatternResolveState.java b/java/java-psi-impl/src/com/intellij/psi/scope/PatternResolveState.java index 32720a6a833f..1758d2807e52 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/PatternResolveState.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/PatternResolveState.java @@ -6,7 +6,7 @@ import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; public enum PatternResolveState { - WHEN_TRUE, WHEN_FALSE, WHEN_BOTH; + WHEN_TRUE, WHEN_FALSE, WHEN_BOTH, WHEN_NONE; public static final Key KEY = Key.create("JavaPatternDeclarationHint"); @@ -20,10 +20,8 @@ public enum PatternResolveState { return WHEN_FALSE; case WHEN_FALSE: return WHEN_TRUE; - case WHEN_BOTH: - return WHEN_BOTH; default: - throw new IllegalStateException("Unexpected value: " + this); + return this; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingPatterns/InstanceOfInSwitch.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingPatterns/InstanceOfInSwitch.java new file mode 100644 index 000000000000..56e8b118bafe --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingPatterns/InstanceOfInSwitch.java @@ -0,0 +1,28 @@ +class X { + void test(Object obj, int x) { + switch (x) { + case 1: + if (!(obj instanceof String s)) return; + System.out.println(s.trim()); + case 2: + if (!(obj instanceof Number s)) return; + System.out.println(s.longValue()); + case 3: + System.out.println(s); + } + } + + void testWhile(Object obj, int x) { + switch (x) { + case 1: + while(!(obj instanceof String s)) { + obj = getNextObject(); + } + System.out.println(s.trim()); + case 2: + System.out.println(s.trim()); + } + } + + native Object getNextObject(); +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsHighlightingTest.java index 442540dec46b..7747cdd50763 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsHighlightingTest.java @@ -27,6 +27,9 @@ public class LightPatternsHighlightingTest extends LightJavaCodeInsightFixtureTe public void testInstanceOfControlFlow() { doTest(); } + public void testInstanceOfInSwitch() { + doTest(); + } public void testReassignPatternVariable() { doTest(); }