From 61df9279ff6adc351d1e8cd81a7e589c9b33ca8b Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 21 Nov 2018 13:56:59 +0100 Subject: [PATCH] [java] value breaks: PSI improvements (IDEA-CR-40172) --- .../daemon/impl/analysis/HighlightUtil.java | 8 +++-- .../com/intellij/psi/PsiBreakStatement.java | 28 +++++++++++---- .../tree/java/PsiBreakStatementImpl.java | 35 +++++++++---------- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 0d8d399dec52..baf426456f60 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -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)) { diff --git a/java/java-psi-api/src/com/intellij/psi/PsiBreakStatement.java b/java/java-psi-api/src/com/intellij/psi/PsiBreakStatement.java index e9874660a1e8..e21ff17ae72c 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiBreakStatement.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiBreakStatement.java @@ -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() { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiBreakStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiBreakStatementImpl.java index 7941c110d748..74425e35753c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiBreakStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiBreakStatementImpl.java @@ -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));