mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
[java][resolve] IDEA-271676 Pattern matching for switch: fix resolve
Fix resolve in PsiSwitchLabelStatementImpl. GitOrigin-RevId: 88d00bf2c7d08f2e3e4950218bcada69d55b0772
This commit is contained in:
committed by
intellij-monorepo-bot
parent
396b542c59
commit
2ca73ddb92
@@ -12,6 +12,9 @@ import com.intellij.psi.tree.ChildRoleBase;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class PsiSwitchLabelStatementImpl extends PsiSwitchLabelStatementBaseImpl implements PsiSwitchLabelStatement {
|
||||
private static final Logger LOG = Logger.getInstance(PsiSwitchLabelStatementImpl.class);
|
||||
@@ -61,14 +64,11 @@ public class PsiSwitchLabelStatementImpl extends PsiSwitchLabelStatementBaseImpl
|
||||
@Override
|
||||
public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
@NotNull ResolveState state,
|
||||
PsiElement lastParent,
|
||||
@Nullable PsiElement lastParent,
|
||||
@NotNull PsiElement place) {
|
||||
if (!super.processDeclarations(processor, state, lastParent, place)) return false;
|
||||
|
||||
// Do not resolve references that come from the list of elements in this case rule
|
||||
if (lastParent instanceof PsiCaseLabelElementList) return true;
|
||||
|
||||
if (isNotImmediateSwitchLabel()) return true;
|
||||
if (!shouldAnalyzePatternVariablesInCaseLabel(place)) return true;
|
||||
|
||||
final PsiCaseLabelElementList patternsInCaseLabel = getCaseLabelElementList();
|
||||
if (patternsInCaseLabel == null) return true;
|
||||
@@ -77,14 +77,33 @@ public class PsiSwitchLabelStatementImpl extends PsiSwitchLabelStatementBaseImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* When the resolving is happening inside a {@link PsiCodeBlock} it traverses through all the case labels,
|
||||
* which is not what is expected for pattern variables, because their scope is bound only to the nearest case handler.
|
||||
* The method checks if this {@link PsiSwitchLabelStatement} is the nearest one to the case handler.
|
||||
*
|
||||
* @return true if the this {@link PsiSwitchLabelStatement} is followed by another {@link PsiSwitchLabelStatement}, false otherwise
|
||||
* Checks if the pattern variables in the case label list can be analyzed. The processing is allowed in the two following cases:
|
||||
* <ol>
|
||||
* <li>The place that is being resolved is a code block. It just wants to build the map of the local and pattern variables in {@code PsiCodeBlockImpl#buildMaps}.</li>
|
||||
* <li>The current {@link PsiSwitchLabelStatement} is the switch label where it's legal to resolve the passed element.
|
||||
* <p>
|
||||
* Read more about scopes of variables in pattern matching for switch statements in
|
||||
* <a href="https://openjdk.java.net/jeps/406#3--Scope-of-pattern-variable-declarations">the JEP</a>.
|
||||
* </p>
|
||||
* </li>
|
||||
* </ol>
|
||||
* @param place element that is being resolved
|
||||
* @return true when the pattern variables in the case label list can be analyzed.
|
||||
*/
|
||||
private boolean isNotImmediateSwitchLabel() {
|
||||
final PsiElement rightNeighbour = PsiTreeUtil.skipWhitespacesForward(this);
|
||||
return rightNeighbour instanceof PsiSwitchLabelStatement;
|
||||
private boolean shouldAnalyzePatternVariablesInCaseLabel(@NotNull PsiElement place) {
|
||||
if (place instanceof PsiCodeBlock) return true;
|
||||
|
||||
final AtomicBoolean thisSwitchLabelIsImmediate = new AtomicBoolean();
|
||||
|
||||
PsiTreeUtil.treeWalkUp(place, getParent(), (currentScope, __) -> {
|
||||
final PsiElement sibling = PsiTreeUtil.skipWhitespacesBackward(currentScope.getPrevSibling());
|
||||
if (sibling == this) {
|
||||
thisSwitchLabelIsImmediate.set(true);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return thisSwitchLabelIsImmediate.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
class Main {
|
||||
|
||||
void statement(Object o) {
|
||||
switch (o) {
|
||||
case Integer n && n > 1:
|
||||
break;
|
||||
case Integer n && n < 1:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int expression(Object o) {
|
||||
return switch (o) {
|
||||
case Integer n && n > 1 -> n;
|
||||
case Integer n && n < 1 -> n;
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
int nestedExpression(Object o, Object o2, int p) {
|
||||
int m = 0;
|
||||
return switch (o) {
|
||||
case Integer n && n > 1 -> switch(o2) {
|
||||
case Integer <error descr="Variable 'm' is already defined in the scope">m</error> && m > 0 -> m + n;
|
||||
case Integer <error descr="Variable 'p' is already defined in the scope">p</error> -> p + n;
|
||||
default -> 0;
|
||||
};
|
||||
case Integer n && n < 1 -> n;
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
void nestedStatement(Object o, Object o2, int p) {
|
||||
int m = 0;
|
||||
switch (o) {
|
||||
case Integer n && n < 1:
|
||||
n ++;
|
||||
case Integer n && n > 1:
|
||||
switch(o2) {
|
||||
case Integer <error descr="Variable 'm' is already defined in the scope">m</error> && m > 0:
|
||||
m += n;
|
||||
case Integer <error descr="Variable 'p' is already defined in the scope">p</error> && p > 0:
|
||||
p += n + m;
|
||||
break;
|
||||
case Integer p1:
|
||||
p += n + m + p1;
|
||||
};
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class Main {
|
||||
final int i = 2;
|
||||
|
||||
void f(Object obj) {
|
||||
switch (obj) {
|
||||
case Integer i: break;
|
||||
case i<caret>:
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,12 @@ public class LightPatternsForSwitchHighlightingTest extends LightJavaCodeInsight
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSameVariableNameInPatternMatchingInSwitch() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile(getTestName(false) + ".java");
|
||||
myFixture.checkHighlighting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,10 @@ public class GotoDeclarationTest extends LightJavaCodeInsightTestCase {
|
||||
doTestPatternMatchingGuard();
|
||||
}
|
||||
|
||||
public void testReferenceFieldInPatternMatchingInSwitchStatement() {
|
||||
doTestPatternMatchingGuard();
|
||||
}
|
||||
|
||||
private void doTestPatternMatchingGuard() {
|
||||
String name = getTestName(false);
|
||||
configureByFile("/codeInsight/gotoDeclaration/" + name + ".java");
|
||||
|
||||
Reference in New Issue
Block a user