[java] value breaks: PSI improvements (IDEA-CR-40172)

This commit is contained in:
Roman Shevchenko
2018-11-21 13:56:59 +01:00
parent 5641cfbf21
commit 61df9279ff
3 changed files with 45 additions and 26 deletions
@@ -783,17 +783,19 @@ public class HighlightUtil extends HighlightUtilBase {
@Nullable
static HighlightInfo checkValueBreakExpression(@NotNull PsiBreakStatement statement, @Nullable PsiExpression expression) {
PsiElement enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(statement);
boolean plainRef = PsiImplUtil.isPlainReference(expression);
if (enclosing instanceof PsiSwitchExpression) {
if (expression == null) {
String message = JavaErrorMessages.message("value.break.missing");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
}
if (PsiTreeUtil.isAncestor(statement.findExitedElement(), enclosing, true)) {
if (plainRef && PsiTreeUtil.isAncestor(((PsiReferenceExpression)expression).resolve(), enclosing, true)) {
String message = JavaErrorMessages.message("break.outside.switch.expr");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
}
}
else if (expression != null && (!PsiImplUtil.isPlainReference(expression) || ((PsiReferenceExpression)expression).resolve() instanceof PsiVariable)) {
else if (expression != null && !plainRef) {
String message = JavaErrorMessages.message("value.break.unexpected");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
}
@@ -814,6 +816,7 @@ public class HighlightUtil extends HighlightUtilBase {
@Nullable
static HighlightInfo checkContinueTarget(@NotNull PsiContinueStatement statement, @NotNull PsiIdentifier label, @NotNull LanguageLevel level) {
PsiStatement continuedStatement = statement.findContinuedStatement();
if (continuedStatement == null) {
String message = JavaErrorMessages.message("unresolved.label", label.getText());
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(label).descriptionAndTooltip(message).create();
@@ -822,6 +825,7 @@ public class HighlightUtil extends HighlightUtilBase {
String message = JavaErrorMessages.message("not.loop.label", label.getText());
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
}
if (level.isAtLeast(LanguageLevel.JDK_12_PREVIEW)) {
PsiElement enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(statement);
if (enclosing instanceof PsiSwitchExpression && PsiTreeUtil.isAncestor(continuedStatement, enclosing, true)) {
@@ -1,6 +1,7 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
/**
@@ -8,14 +9,21 @@ import org.jetbrains.annotations.Nullable;
*/
public interface PsiBreakStatement extends PsiStatement {
/**
* Returns the label identifier iff it is present and the statement is not inside a switch expression, {@code null} otherwise.
*
* @see #getExpression()
* Returns the label expression iff it is present, is an unqualified reference, and the statement is not inside a switch expression,
* {@code null} otherwise.
*/
@Nullable PsiIdentifier getLabelIdentifier();
@Nullable PsiReferenceExpression getLabelExpression();
/**
* Returns the label/value expression, or {@code null} if the statement is empty.
* Returns the value expression iff it is present and the statement is inside a switch expression, {@code null} otherwise.
*/
@Nullable PsiExpression getValueExpression();
/**
* Returns the label or value expression, or {@code null} if the statement is empty.
*
* @see #getLabelExpression()
* @see #getValueExpression()
*/
@Nullable PsiExpression getExpression();
@@ -25,7 +33,15 @@ public interface PsiBreakStatement extends PsiStatement {
*/
@Nullable PsiElement findExitedElement();
/** @deprecated doesn't support "switch" expressions; use {@link #findExitedElement()} instead */
/** @deprecated doesn't support switch expressions; use {@link #getLabelExpression()}} instead */
@Deprecated
@SuppressWarnings("DeprecatedIsStillUsed")
default PsiIdentifier getLabelIdentifier() {
PsiReferenceExpression expression = getLabelExpression();
return expression != null ? PsiTreeUtil.getChildOfType(expression, PsiIdentifier.class) : null;
}
/** @deprecated doesn't support switch expressions; use {@link #findExitedElement()} instead */
@Deprecated
@SuppressWarnings("DeprecatedIsStillUsed")
default PsiStatement findExitedStatement() {
@@ -8,7 +8,6 @@ import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.tree.ChildRoleBase;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
public class PsiBreakStatementImpl extends CompositePsiElement implements PsiBreakStatement {
@@ -19,9 +18,17 @@ public class PsiBreakStatementImpl extends CompositePsiElement implements PsiBre
}
@Override
public PsiIdentifier getLabelIdentifier() {
PsiIdentifier labelId = labelId();
return labelId != null && !(findExitedElement() instanceof PsiSwitchExpression) ? labelId : null;
public PsiReferenceExpression getLabelExpression() {
PsiExpression expression = getExpression();
boolean isLabel = PsiImplUtil.isPlainReference(expression) && !(PsiImplUtil.findEnclosingSwitchOrLoop(this) instanceof PsiSwitchExpression);
return isLabel ? (PsiReferenceExpression)expression : null;
}
@Override
public PsiExpression getValueExpression() {
PsiExpression expression = getExpression();
boolean isValue = expression != null && PsiImplUtil.findEnclosingSwitchOrLoop(this) instanceof PsiSwitchExpression;
return isValue ? expression : null;
}
@Override
@@ -31,29 +38,21 @@ public class PsiBreakStatementImpl extends CompositePsiElement implements PsiBre
@Override
public PsiElement findExitedElement() {
PsiIdentifier label = labelId();
if (label == null) {
return PsiImplUtil.findEnclosingSwitchOrLoop(this);
PsiElement enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(this);
PsiExpression expression = getExpression();
if (enclosing == null || enclosing instanceof PsiSwitchExpression || !PsiImplUtil.isPlainReference(expression)) {
return enclosing;
}
PsiLabeledStatement labeled = PsiImplUtil.findEnclosingLabeledStatement(this, label.getText());
PsiLabeledStatement labeled = PsiImplUtil.findEnclosingLabeledStatement(enclosing, expression.getText());
if (labeled != null) {
return labeled.getStatement();
}
PsiElement enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(this);
if (enclosing instanceof PsiSwitchExpression) {
return enclosing;
}
return null;
}
private PsiIdentifier labelId() {
PsiExpression expr = getExpression();
return PsiImplUtil.isPlainReference(expr) ? PsiTreeUtil.getChildOfType(expr, PsiIdentifier.class) : null;
}
@Override
public ASTNode findChildByRole(int role) {
LOG.assertTrue(ChildRole.isUnique(role));