mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
[java] 'yield' statement: basic highlighting (IDEA-216410)
GitOrigin-RevId: 4edae910f16a27c2a46068c2d8b6fce4674e0571
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6941d27505
commit
06d3d41999
+35
-2
@@ -809,11 +809,23 @@ public class HighlightUtil extends HighlightUtilBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkValueBreakExpression(@NotNull PsiBreakStatement statement, @Nullable PsiExpression expression) {
|
||||
static HighlightInfo checkValueBreakExpression(@NotNull PsiBreakStatement statement,
|
||||
@Nullable PsiExpression expression,
|
||||
@NotNull LanguageLevel languageLevel) {
|
||||
PsiElement enclosing = PsiImplUtil.findEnclosingSwitchOrLoop(statement);
|
||||
boolean plainRef = PsiImplUtil.isUnqualifiedReference(expression);
|
||||
|
||||
if (enclosing instanceof PsiSwitchExpression) {
|
||||
if (languageLevel == LanguageLevel.JDK_13_PREVIEW) {
|
||||
if (expression == null || plainRef && ((PsiReferenceExpression)expression).resolve() instanceof PsiLabeledStatement) {
|
||||
String message = JavaErrorMessages.message("break.outside.switch.expr");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
|
||||
}
|
||||
else {
|
||||
String message = "Value breaks are superseded by 'yield' statements";
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
|
||||
}
|
||||
}
|
||||
if (expression == null) {
|
||||
String message = JavaErrorMessages.message("value.break.missing");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
|
||||
@@ -831,6 +843,27 @@ public class HighlightUtil extends HighlightUtilBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkYieldOutsideSwitchExpression(@NotNull PsiYieldStatement statement) {
|
||||
if (statement.findEnclosingExpression() == null) {
|
||||
String message = JavaErrorMessages.message("yield.unexpected");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(message).create();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkYieldExpressionType(@NotNull PsiYieldStatement statement) {
|
||||
PsiExpression expression = statement.getExpression();
|
||||
if (expression != null && PsiType.VOID.equals(expression.getType())) {
|
||||
String message = JavaErrorMessages.message("yield.void");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(message).create();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkContinueOutsideLoop(@NotNull PsiContinueStatement statement, LanguageLevel languageLevel) {
|
||||
if (PsiImplUtil.findEnclosingLoop(statement) == null) {
|
||||
@@ -3171,7 +3204,7 @@ public class HighlightUtil extends HighlightUtilBase {
|
||||
}
|
||||
|
||||
private boolean isSufficient(LanguageLevel useSiteLevel) {
|
||||
return level.isPreview() ? useSiteLevel == level : useSiteLevel.isAtLeast(level);
|
||||
return useSiteLevel.isAtLeast(level) && (!level.isPreview() || useSiteLevel.isPreview());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -414,10 +414,17 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
myHolder.add(HighlightUtil.checkBreakOutsideSwitchOrLoop(statement));
|
||||
}
|
||||
if (!myHolder.hasErrorResults() && Feature.ENHANCED_SWITCH.isAvailable(myFile)) {
|
||||
myHolder.add(HighlightUtil.checkValueBreakExpression(statement, expression));
|
||||
myHolder.add(HighlightUtil.checkValueBreakExpression(statement, expression, myLanguageLevel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitYieldStatement(PsiYieldStatement statement) {
|
||||
super.visitYieldStatement(statement);
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkYieldOutsideSwitchExpression(statement));
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkYieldExpressionType(statement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
super.visitClass(aClass);
|
||||
|
||||
@@ -378,8 +378,13 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
private static void collectSwitchResultExpressions(@NotNull List<? super PsiExpression> result, @NotNull PsiElement container) {
|
||||
List<PsiBreakStatement> breaks = new ArrayList<>();
|
||||
addStatements(breaks, container, PsiBreakStatement.class, element -> element instanceof PsiSwitchBlock);
|
||||
for (PsiBreakStatement aBreak : breaks) {
|
||||
ContainerUtil.addIfNotNull(result, aBreak.getExpression());
|
||||
for (PsiBreakStatement statement : breaks) {
|
||||
ContainerUtil.addIfNotNull(result, statement.getExpression());
|
||||
}
|
||||
List<PsiYieldStatement> yields = new ArrayList<>();
|
||||
addStatements(yields, container, PsiYieldStatement.class, element -> false);
|
||||
for (PsiYieldStatement statement : yields) {
|
||||
ContainerUtil.addIfNotNull(result, statement.getExpression());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,5 +13,5 @@ jdk.11.language.level.description=11 - Local variable syntax for lambda paramete
|
||||
jdk.12.language.level.description=12 - No new language features
|
||||
jdk.12.preview.language.level.description=12 (Preview) - Switch expressions
|
||||
jdk.13.language.level.description=13 - No new language features
|
||||
jdk.13.preview.language.level.description=13 (Preview) - Text blocks
|
||||
jdk.13.preview.language.level.description=13 (Preview) - Switch expressions, text blocks
|
||||
jdk.X.language.level.description=X - Experimental features
|
||||
|
||||
@@ -38,7 +38,8 @@ public class JavaLexer extends LexerBase {
|
||||
public static boolean isSoftKeyword(CharSequence id, @NotNull LanguageLevel level) {
|
||||
return id != null &&
|
||||
(level.isAtLeast(LanguageLevel.JDK_1_9) && JAVA9_KEYWORDS.contains(id) ||
|
||||
level.isAtLeast(LanguageLevel.JDK_10) && VAR.contentEquals(id));
|
||||
level.isAtLeast(LanguageLevel.JDK_10) && VAR.contentEquals(id) ||
|
||||
level.isAtLeast(LanguageLevel.JDK_13_PREVIEW) && YIELD.contentEquals(id));
|
||||
}
|
||||
|
||||
private final _JavaLexer myFlexLexer;
|
||||
|
||||
@@ -233,6 +233,8 @@ variable.already.defined=Variable ''{0}'' is already defined in the scope
|
||||
break.outside.switch.or.loop=Break outside switch or loop
|
||||
value.break.unexpected=Value break outside switch expression
|
||||
value.break.missing=Missing break value
|
||||
yield.unexpected=Yield outside of switch expression
|
||||
yield.void=Expression type should not be 'void'
|
||||
break.outside.switch.expr=Break outside of enclosing switch expression
|
||||
continue.outside.loop=Continue outside of loop
|
||||
continue.outside.switch.expr=Continue outside of enclosing switch expression
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
class YieldStatements {
|
||||
void m(int i) {
|
||||
System.out.println(switch (i) {
|
||||
case 0: yield "zero";
|
||||
default: <error descr="Value breaks are superseded by 'yield' statements">break "many";</error>
|
||||
});
|
||||
|
||||
switch (i) {
|
||||
default: <error descr="Yield outside of switch expression">yield 0;</error>
|
||||
}
|
||||
System.out.println(switch (i) {
|
||||
default:
|
||||
Runnable r = () -> { <error descr="Yield outside of switch expression">yield 0;</error> };
|
||||
r.run();
|
||||
yield 0;
|
||||
});
|
||||
System.out.println(switch (i) {
|
||||
default: switch (i) {
|
||||
default: yield "0";
|
||||
}
|
||||
});
|
||||
|
||||
out: while (true) {
|
||||
System.out.println(switch (i) {
|
||||
case 0: <error descr="Break outside of enclosing switch expression">break;</error>
|
||||
case 1: <error descr="Value breaks are superseded by 'yield' statements">break i;</error>
|
||||
default: <error descr="Break outside of enclosing switch expression">break out;</error>
|
||||
});
|
||||
}
|
||||
|
||||
System.out.println(switch (i) {
|
||||
default: yield <error descr="Expression type should not be 'void'">m(0)</error>;
|
||||
});
|
||||
|
||||
int yield = i;
|
||||
i = switch (i) {
|
||||
default: yield yield;
|
||||
};
|
||||
}
|
||||
}
|
||||
+15
-1
@@ -1,7 +1,10 @@
|
||||
// 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.java.codeInsight.daemon
|
||||
|
||||
import com.intellij.JavaTestUtil
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtension
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
|
||||
|
||||
class JavaSwitchExpressionsHighlightingTest : LightJavaCodeInsightFixtureTestCase() {
|
||||
@@ -18,6 +21,17 @@ class JavaSwitchExpressionsHighlightingTest : LightJavaCodeInsightFixtureTestCas
|
||||
fun testEnhancedSwitchUnreachable() = doTest()
|
||||
fun testSwitchExpressionHasResult() = doTest()
|
||||
|
||||
fun testYieldStatements() = try {
|
||||
level(LanguageLevel.JDK_13_PREVIEW)
|
||||
doTest()
|
||||
}
|
||||
finally {
|
||||
level(LanguageLevel.JDK_12_PREVIEW)
|
||||
}
|
||||
|
||||
private fun level(level: LanguageLevel) =
|
||||
ModuleRootModificationUtil.updateModel(module) { it.getModuleExtension(LanguageLevelModuleExtension::class.java).languageLevel = level }
|
||||
|
||||
private fun doTest() {
|
||||
myFixture.configureByFile("${getTestName(false)}.java")
|
||||
myFixture.checkHighlighting()
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ public class ControlFlowUtils {
|
||||
if (statement == null) {
|
||||
return true;
|
||||
}
|
||||
if (statement instanceof PsiBreakStatement || statement instanceof PsiContinueStatement ||
|
||||
if (statement instanceof PsiBreakStatement || statement instanceof PsiContinueStatement || statement instanceof PsiYieldStatement ||
|
||||
statement instanceof PsiReturnStatement || statement instanceof PsiThrowStatement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user