mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
[java] fixes and unifies 'break'/'continue' highlighting
GitOrigin-RevId: 4472c012bbc690ce96bdc43baa4075c4c14c1c62
This commit is contained in:
committed by
intellij-monorepo-bot
parent
624ff3b0a7
commit
83258b1714
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,12 +10,12 @@ class YieldStatements {
|
||||
default: <error descr="Yield outside of switch expression">yield 0;</error>
|
||||
}
|
||||
|
||||
System.out.println(switch (i) {
|
||||
out: System.out.println(switch (i) {
|
||||
case 1 -> { while (true) yield ref; }
|
||||
case 2 -> { while (true) break <error descr="Undefined label: 'wtf'">wtf</error>; }
|
||||
case 3 -> { yield ref; }
|
||||
case 4 -> { yield (ref); }
|
||||
case 5 -> { <error descr="Break outside of enclosing switch expression">break wtf;</error> }
|
||||
case 5 -> { break <error descr="Undefined label: 'wtf'">wtf</error>; }
|
||||
case 6 -> {
|
||||
int a = 0;
|
||||
a: switch (0) { default: yield a; }
|
||||
@@ -34,6 +34,9 @@ class YieldStatements {
|
||||
yield yield;
|
||||
}
|
||||
case 11 -> { yield <error descr="Expression type should not be 'void'">m(0)</error>; }
|
||||
case 12 -> {
|
||||
switch (i) { default: <error descr="Break outside of enclosing switch expression">break out;</error>; }
|
||||
}
|
||||
default -> throw new RuntimeException();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user