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 444b73295ca1..32f133ed83e0 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 @@ -515,7 +515,7 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable static HighlightInfo checkReturnFromSwitchExpr(@NotNull PsiStatement statement) { - if (PsiImplUtil.findEnclosingSwitchOrLoop(statement) instanceof PsiSwitchExpression) { + if (PsiImplUtil.findEnclosingSwitchExpression(statement) != null) { String message = JavaErrorMessages.message("return.outside.switch.expr"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); } @@ -796,24 +796,9 @@ public class HighlightUtil extends HighlightUtilBase { @Nullable static HighlightInfo checkBreakTarget(@NotNull PsiBreakStatement statement, @NotNull LanguageLevel languageLevel) { - if (statement.findExitedStatement() == null) { - if (Feature.ENHANCED_SWITCH.isSufficient(languageLevel) && PsiImplUtil.findEnclosingSwitchOrLoop(statement) instanceof PsiSwitchExpression) { - String message = JavaErrorMessages.message("break.outside.switch.expr"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); - } - - PsiIdentifier label = statement.getLabelIdentifier(); - if (label != null) { - String message = JavaErrorMessages.message("unresolved.label", label.getText()); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(label).descriptionAndTooltip(message).create(); - } - else { - String message = JavaErrorMessages.message("break.outside.switch.or.loop"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); - } - } - - return null; + return checkBreakOrContinueTarget(statement, statement.getLabelIdentifier(), statement.findExitedStatement(), languageLevel, + "break.outside.switch.or.loop", + "break.outside.switch.expr"); } @Nullable @@ -838,42 +823,45 @@ public class HighlightUtil extends HighlightUtilBase { } @Nullable - static HighlightInfo checkContinueOutsideLoop(@NotNull PsiContinueStatement statement, LanguageLevel languageLevel) { - if (PsiImplUtil.findEnclosingLoop(statement) == null) { - String message = JavaErrorMessages.message("continue.outside.loop"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); - } - - return checkContinueOutsideOfSwitchExpression(statement, statement.findContinuedStatement(), languageLevel); - } - - @Nullable - static HighlightInfo checkContinueTarget(@NotNull PsiContinueStatement statement, @NotNull PsiIdentifier label, @NotNull LanguageLevel level) { + static HighlightInfo checkContinueTarget(@NotNull PsiContinueStatement statement, @NotNull LanguageLevel languageLevel) { PsiStatement continuedStatement = statement.findContinuedStatement(); + PsiIdentifier label = statement.getLabelIdentifier(); - if (continuedStatement == null) { - String message = JavaErrorMessages.message("unresolved.label", label.getText()); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(label).descriptionAndTooltip(message).create(); - } - if (!(continuedStatement instanceof PsiLoopStatement)) { + if (label != null && continuedStatement != null && !(continuedStatement instanceof PsiLoopStatement)) { String message = JavaErrorMessages.message("not.loop.label", label.getText()); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); } - return checkContinueOutsideOfSwitchExpression(statement, continuedStatement, level); + return checkBreakOrContinueTarget(statement, label, continuedStatement, languageLevel, + "continue.outside.loop", + "continue.outside.switch.expr"); } - private static HighlightInfo checkContinueOutsideOfSwitchExpression(PsiContinueStatement statement, - PsiStatement continuedStatement, - LanguageLevel level) { + @Nullable + private static HighlightInfo checkBreakOrContinueTarget(PsiStatement statement, + @Nullable PsiIdentifier label, + @Nullable PsiStatement target, + LanguageLevel level, + @PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String misplacedKey, + @PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) String crossingKey) { + if (target == null && label != null) { + String message = JavaErrorMessages.message("unresolved.label", label.getText()); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(label).descriptionAndTooltip(message).create(); + } + if (Feature.ENHANCED_SWITCH.isSufficient(level)) { - PsiElement enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(statement); - if (enclosing instanceof PsiSwitchExpression && PsiTreeUtil.isAncestor(continuedStatement, enclosing, true)) { - String message = JavaErrorMessages.message("continue.outside.switch.expr"); + PsiSwitchExpression expression = PsiImplUtil.findEnclosingSwitchExpression(statement); + if (expression != null && (target == null || PsiTreeUtil.isAncestor(target, expression, true))) { + String message = JavaErrorMessages.message(crossingKey); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); } } + if (target == null) { + String message = JavaErrorMessages.message(misplacedKey); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create(); + } + return null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 4a850724b063..f03d3b61c8cb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -461,11 +461,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitContinueStatement(PsiContinueStatement statement) { super.visitContinueStatement(statement); - if (!myHolder.hasErrorResults()) { - PsiIdentifier label = statement.getLabelIdentifier(); - myHolder.add(label == null ? HighlightUtil.checkContinueOutsideLoop(statement, myLanguageLevel) - : HighlightUtil.checkContinueTarget(statement, label, myLanguageLevel)); - } + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkContinueTarget(statement, myLanguageLevel)); } @Override diff --git a/java/java-psi-api/src/com/intellij/psi/PsiContinueStatement.java b/java/java-psi-api/src/com/intellij/psi/PsiContinueStatement.java index d3b215e2390f..3b5a2b682acb 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiContinueStatement.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiContinueStatement.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2019 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 org.jetbrains.annotations.Nullable; @@ -22,19 +8,13 @@ import org.jetbrains.annotations.Nullable; */ public interface PsiContinueStatement extends PsiStatement { /** - * Returns the identifier representing the label specified on the statement. - * - * @return the identifier for the label, or null if the statement has no label. + * Returns an identifier element containing the statement's target label, if any. */ - @Nullable - PsiIdentifier getLabelIdentifier(); + @Nullable PsiIdentifier getLabelIdentifier(); /** * Returns the statement instance ({@link PsiForStatement}, {@link PsiWhileStatement} etc.) representing * the statement to the next iteration of which {@code continue} transfers control. - * - * @return the statement instance, or null if the statement is not valid in the context where it is located. */ - @Nullable - PsiStatement findContinuedStatement(); -} + @Nullable PsiStatement findContinuedStatement(); +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 218bf4b99c66..b33edc992879 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -1,4 +1,4 @@ -// 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. +// Copyright 2000-2019 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.impl; import com.intellij.codeInsight.AnnotationTargetUtil; @@ -39,7 +39,6 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.PairFunction; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -652,11 +651,6 @@ public class PsiImplUtil { } } - @Contract("null -> false") - public static boolean isUnqualifiedReference(@Nullable PsiExpression expression) { - return expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).getQualifierExpression() == null; - } - @Nullable public static PsiLoopStatement findEnclosingLoop(@NotNull PsiElement start) { for (PsiElement e = start; !isCodeBoundary(e); e = e.getParent()) { @@ -666,9 +660,17 @@ public class PsiImplUtil { } @Nullable - public static PsiElement findEnclosingSwitchOrLoop(@NotNull PsiElement start) { + public static PsiStatement findEnclosingSwitchOrLoop(@NotNull PsiElement start) { for (PsiElement e = start; !isCodeBoundary(e); e = e.getParent()) { - if (e instanceof PsiSwitchBlock || e instanceof PsiLoopStatement) return e; + if (e instanceof PsiSwitchStatement || e instanceof PsiLoopStatement) return (PsiStatement)e; + } + return null; + } + + @Nullable + public static PsiSwitchExpression findEnclosingSwitchExpression(@NotNull PsiElement start) { + for (PsiElement e = start; !isCodeBoundary(e); e = e.getParent()) { + if (e instanceof PsiSwitchExpression) return (PsiSwitchExpression)e; } return null; } 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 431da9493f95..a871dd9dd96c 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 @@ -27,18 +27,14 @@ public class PsiBreakStatementImpl extends CompositePsiElement implements PsiBre @Nullable @Override public PsiStatement findExitedStatement() { - PsiElement enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(this); - if (enclosing instanceof PsiSwitchExpression) { - return null; - } - PsiIdentifier label = getLabelIdentifier(); if (label != null) { PsiLabeledStatement labeled = PsiImplUtil.findEnclosingLabeledStatement(this, label.getText()); return labeled != null ? labeled.getStatement() : null; } - - return (PsiStatement)enclosing; + else { + return PsiImplUtil.findEnclosingSwitchOrLoop(this); + } } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiContinueStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiContinueStatementImpl.java index 013cef2f4e2b..cdb5d0f5cbf1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiContinueStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiContinueStatementImpl.java @@ -1,4 +1,4 @@ -// 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. +// Copyright 2000-2019 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.impl.source.tree.java; import com.intellij.lang.ASTNode; @@ -29,16 +29,13 @@ public class PsiContinueStatementImpl extends CompositePsiElement implements Psi @Override public PsiStatement findContinuedStatement() { PsiIdentifier label = getLabelIdentifier(); - if (label == null) { + if (label != null) { + PsiLabeledStatement labeled = PsiImplUtil.findEnclosingLabeledStatement(this, label.getText()); + return labeled != null ? labeled.getStatement() : null; + } + else { return PsiImplUtil.findEnclosingLoop(this); } - - PsiLabeledStatement labeled = PsiImplUtil.findEnclosingLabeledStatement(this, label.getText()); - if (labeled != null) { - return labeled.getStatement(); - } - - return null; } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiYieldStatementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiYieldStatementImpl.java index 5b114da21b66..b3edfecdd83d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiYieldStatementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiYieldStatementImpl.java @@ -22,12 +22,7 @@ public class PsiYieldStatementImpl extends CompositePsiElement implements PsiYie @Nullable @Override public PsiSwitchExpression findEnclosingExpression() { - PsiElement element = this, enclosing; - while (element != null && (enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(element)) != null) { - if (enclosing instanceof PsiSwitchExpression) return (PsiSwitchExpression)enclosing; - element = enclosing.getParent(); - } - return null; + return PsiImplUtil.findEnclosingSwitchExpression(this); } @Override diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java index 9450e73d08d5..04593e8a837f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/YieldStatements.java @@ -10,12 +10,12 @@ class YieldStatements { default: yield 0; } - System.out.println(switch (i) { + out: System.out.println(switch (i) { case 1 -> { while (true) yield ref; } case 2 -> { while (true) break wtf; } case 3 -> { yield ref; } case 4 -> { yield (ref); } - case 5 -> { break wtf; } + case 5 -> { break wtf; } case 6 -> { int a = 0; a: switch (0) { default: yield a; } @@ -34,6 +34,9 @@ class YieldStatements { yield yield; } case 11 -> { yield m(0); } + case 12 -> { + switch (i) { default: break out;; } + } default -> throw new RuntimeException(); });