mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] SwitchBlockHighlightingModel.checkSwitchBlockStatements migrated
Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: 463b1549d45bf98586e6ae9dafb4bc4b330bbe52
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2da31596ac
commit
e6691d9ea8
@@ -314,6 +314,8 @@ switch.expression.no.result=Switch expression does not have any result expressio
|
||||
switch.expression.should.produce.result=Switch expression should produce a result in all execution paths
|
||||
switch.expression.incompatible.type=Bad type in switch expression: {0} cannot be converted to {1}
|
||||
switch.expression.cannot.be.void=Target type for switch expression cannot be void
|
||||
switch.label.expected=Statement must be prepended with a case label
|
||||
switch.different.case.kinds=Different 'case' kinds used in 'switch'
|
||||
|
||||
guard.misplaced=Guard is allowed after patterns only
|
||||
guard.evaluated.to.false=Case label has a guard that is a constant expression with value 'false'
|
||||
|
||||
+59
@@ -1729,4 +1729,63 @@ final class ExpressionChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkSwitchBlockStatements(@NotNull PsiSwitchBlock block) {
|
||||
PsiCodeBlock body = block.getBody();
|
||||
if (body == null) return;
|
||||
PsiElement first = PsiTreeUtil.skipWhitespacesAndCommentsForward(body.getLBrace());
|
||||
if (first != null && !(first instanceof PsiSwitchLabelStatementBase) && !PsiUtil.isJavaToken(first, JavaTokenType.RBRACE)) {
|
||||
myVisitor.report(JavaErrorKinds.SWITCH_LABEL_EXPECTED.create(first));
|
||||
}
|
||||
PsiElement element = first;
|
||||
PsiStatement alien = null;
|
||||
boolean classicLabels = false;
|
||||
boolean enhancedLabels = false;
|
||||
boolean levelChecked = false;
|
||||
while (element != null && !PsiUtil.isJavaToken(element, JavaTokenType.RBRACE)) {
|
||||
if (element instanceof PsiSwitchLabeledRuleStatement) {
|
||||
if (!levelChecked) {
|
||||
myVisitor.checkFeature(element, JavaFeature.ENHANCED_SWITCH);
|
||||
if (myVisitor.hasErrorResults()) return;
|
||||
levelChecked = true;
|
||||
}
|
||||
if (classicLabels) {
|
||||
alien = (PsiStatement)element;
|
||||
break;
|
||||
}
|
||||
enhancedLabels = true;
|
||||
}
|
||||
else if (element instanceof PsiStatement statement) {
|
||||
if (enhancedLabels) {
|
||||
//let's not highlight twice
|
||||
if (statement instanceof PsiSwitchLabelStatement labelStatement &&
|
||||
labelStatement.getChildren().length != 0 &&
|
||||
labelStatement.getChildren()[labelStatement.getChildren().length - 1] instanceof PsiErrorElement errorElement &&
|
||||
errorElement.getErrorDescription().startsWith(JavaPsiBundle.message("expected.colon.or.arrow"))) {
|
||||
break;
|
||||
}
|
||||
alien = statement;
|
||||
break;
|
||||
}
|
||||
classicLabels = true;
|
||||
}
|
||||
|
||||
if (!levelChecked && element instanceof PsiSwitchLabelStatementBase label) {
|
||||
@Nullable PsiCaseLabelElementList values = label.getCaseLabelElementList();
|
||||
if (values != null && values.getElementCount() > 1) {
|
||||
myVisitor.checkFeature(values, JavaFeature.ENHANCED_SWITCH);
|
||||
if (myVisitor.hasErrorResults()) return;
|
||||
levelChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
element = PsiTreeUtil.skipWhitespacesAndCommentsForward(element);
|
||||
}
|
||||
if (alien == null) return;
|
||||
if (enhancedLabels && !(alien instanceof PsiSwitchLabelStatementBase)) {
|
||||
myVisitor.report(JavaErrorKinds.SWITCH_LABEL_EXPECTED.create(alien));
|
||||
return;
|
||||
}
|
||||
myVisitor.report(JavaErrorKinds.SWITCH_DIFFERENT_CASE_KINDS.create(alien));
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -628,6 +628,17 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
if (!hasErrorResults()) checkFeature(expression, JavaFeature.SWITCH_EXPRESSION);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkSwitchExpressionReturnTypeCompatible(expression);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkSwitchExpressionHasResult(expression);
|
||||
checkSwitchBlock(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitchStatement(@NotNull PsiSwitchStatement statement) {
|
||||
super.visitSwitchStatement(statement);
|
||||
checkSwitchBlock(statement);
|
||||
}
|
||||
|
||||
private void checkSwitchBlock(@NotNull PsiSwitchBlock block) {
|
||||
if (!hasErrorResults()) myExpressionChecker.checkSwitchBlockStatements(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
@@ -923,6 +923,8 @@ public final class JavaErrorKinds {
|
||||
public static final Parameterized<PsiExpression, JavaIncompatibleTypeErrorContext> SWITCH_EXPRESSION_INCOMPATIBLE_TYPE =
|
||||
parameterized(PsiExpression.class, JavaIncompatibleTypeErrorContext.class, "switch.expression.incompatible.type")
|
||||
.withRawDescription((expr, context) -> message("switch.expression.incompatible.type", formatType(context.rType()), formatType(context.lType())));
|
||||
public static final Simple<PsiElement> SWITCH_LABEL_EXPECTED = error(PsiElement.class, "switch.label.expected");
|
||||
public static final Simple<PsiElement> SWITCH_DIFFERENT_CASE_KINDS = error("switch.different.case.kinds");
|
||||
|
||||
public static final Simple<PsiReferenceExpression> EXPRESSION_EXPECTED = error("expression.expected");
|
||||
public static final Parameterized<PsiReferenceExpression, PsiSuperExpression> EXPRESSION_SUPER_UNQUALIFIED_DEFAULT_METHOD =
|
||||
|
||||
-1
@@ -327,7 +327,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
private void checkSwitchBlock(@NotNull PsiSwitchBlock switchBlock) {
|
||||
SwitchBlockHighlightingModel model = SwitchBlockHighlightingModel.createInstance(myLanguageLevel, switchBlock, myFile);
|
||||
if (model == null) return;
|
||||
if (!hasErrorResults()) model.checkSwitchBlockStatements(myErrorSink);
|
||||
if (!hasErrorResults()) model.checkSwitchSelectorType(myErrorSink);
|
||||
if (!hasErrorResults()) model.checkSwitchLabelValues(myErrorSink);
|
||||
}
|
||||
|
||||
+4
@@ -223,6 +223,10 @@ final class JavaErrorFixProvider {
|
||||
error -> myFactory.createDeleteFix(error.psi(), QuickFixBundle.message("delete.unreachable.statement.fix.text")));
|
||||
fix(STATEMENT_UNREACHABLE_LOOP_BODY, error -> myFactory.createSimplifyBooleanFix(error.psi(), false));
|
||||
fix(FOREACH_NOT_APPLICABLE, error -> myFactory.createNotIterableForEachLoopFix(error.psi()));
|
||||
fix(SWITCH_LABEL_EXPECTED, error -> {
|
||||
PsiSwitchLabeledRuleStatement previousRule = PsiTreeUtil.getPrevSiblingOfType(error.psi(), PsiSwitchLabeledRuleStatement.class);
|
||||
return previousRule == null ? null : myFactory.createWrapSwitchRuleStatementsIntoBlockFix(previousRule);
|
||||
});
|
||||
}
|
||||
|
||||
private void createMethodFixes() {
|
||||
|
||||
-72
@@ -7,7 +7,6 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.modcommand.ModCommandAction;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
@@ -80,77 +79,6 @@ public class SwitchBlockHighlightingModel {
|
||||
return found.get();
|
||||
}
|
||||
|
||||
void checkSwitchBlockStatements(@NotNull Consumer<? super HighlightInfo.Builder> errorSink) {
|
||||
PsiCodeBlock body = myBlock.getBody();
|
||||
if (body == null) return;
|
||||
PsiElement first = PsiTreeUtil.skipWhitespacesAndCommentsForward(body.getLBrace());
|
||||
if (first != null && !(first instanceof PsiSwitchLabelStatementBase) && !PsiUtil.isJavaToken(first, JavaTokenType.RBRACE)) {
|
||||
errorSink.accept(createError(first, JavaErrorBundle.message("statement.must.be.prepended.with.case.label")));
|
||||
}
|
||||
PsiElement element = first;
|
||||
PsiStatement alien = null;
|
||||
boolean classicLabels = false;
|
||||
boolean enhancedLabels = false;
|
||||
boolean levelChecked = false;
|
||||
while (element != null && !PsiUtil.isJavaToken(element, JavaTokenType.RBRACE)) {
|
||||
if (element instanceof PsiSwitchLabeledRuleStatement) {
|
||||
if (!levelChecked) {
|
||||
HighlightInfo.Builder info = HighlightUtil.checkFeature(element, JavaFeature.ENHANCED_SWITCH, myLevel, myFile);
|
||||
if (info != null) {
|
||||
errorSink.accept(info);
|
||||
return;
|
||||
}
|
||||
levelChecked = true;
|
||||
}
|
||||
if (classicLabels) {
|
||||
alien = (PsiStatement)element;
|
||||
break;
|
||||
}
|
||||
enhancedLabels = true;
|
||||
}
|
||||
else if (element instanceof PsiStatement statement) {
|
||||
if (enhancedLabels) {
|
||||
//let's not highlight twice
|
||||
if (statement instanceof PsiSwitchLabelStatement labelStatement &&
|
||||
labelStatement.getChildren().length != 0 &&
|
||||
labelStatement.getChildren()[labelStatement.getChildren().length - 1] instanceof PsiErrorElement errorElement &&
|
||||
errorElement.getErrorDescription().startsWith(JavaPsiBundle.message("expected.colon.or.arrow"))) {
|
||||
break;
|
||||
}
|
||||
alien = statement;
|
||||
break;
|
||||
}
|
||||
classicLabels = true;
|
||||
}
|
||||
|
||||
if (!levelChecked && element instanceof PsiSwitchLabelStatementBase label) {
|
||||
@Nullable PsiCaseLabelElementList values = label.getCaseLabelElementList();
|
||||
if (values != null && values.getElementCount() > 1) {
|
||||
HighlightInfo.Builder info = HighlightUtil.checkFeature(values, JavaFeature.ENHANCED_SWITCH, myLevel, myFile);
|
||||
if (info != null) {
|
||||
errorSink.accept(info);
|
||||
return;
|
||||
}
|
||||
levelChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
element = PsiTreeUtil.skipWhitespacesAndCommentsForward(element);
|
||||
}
|
||||
if (alien == null) return;
|
||||
if (enhancedLabels && !(alien instanceof PsiSwitchLabelStatementBase)) {
|
||||
PsiSwitchLabeledRuleStatement previousRule = PsiTreeUtil.getPrevSiblingOfType(alien, PsiSwitchLabeledRuleStatement.class);
|
||||
HighlightInfo.Builder info = createError(alien, JavaErrorBundle.message("statement.must.be.prepended.with.case.label"));
|
||||
if (previousRule != null) {
|
||||
IntentionAction action = getFixFactory().createWrapSwitchRuleStatementsIntoBlockFix(previousRule);
|
||||
info.registerFix(action, null, null, null, null);
|
||||
}
|
||||
errorSink.accept(info);
|
||||
return;
|
||||
}
|
||||
errorSink.accept(createError(alien, JavaErrorBundle.message("different.case.kinds.in.switch")));
|
||||
}
|
||||
|
||||
void checkSwitchSelectorType(@NotNull Consumer<? super HighlightInfo.Builder> errorSink) {
|
||||
SelectorKind kind = getSwitchSelectorKind();
|
||||
if (kind == SelectorKind.INT) return;
|
||||
|
||||
@@ -97,8 +97,6 @@ identifier.is.not.allowed.here=Identifier is not allowed here
|
||||
illegal.forward.reference=Cannot read value of field ''{0}'' before the field''s definition
|
||||
unknown.class=Unknown class: ''{0}''
|
||||
illegal.type.void=Illegal type: 'void'
|
||||
statement.must.be.prepended.with.case.label=Statement must be prepended with case label
|
||||
different.case.kinds.in.switch=Different 'case' kinds used in 'switch'
|
||||
numeric.overflow.in.expression=Numeric overflow in expression
|
||||
static.member.accessed.via.instance.reference=Static member ''{0}.{1}'' accessed via instance reference
|
||||
deprecated.symbol=''{0}'' is deprecated
|
||||
|
||||
+3
-3
@@ -11,15 +11,15 @@ class SwitchStatement {
|
||||
switch (0) {
|
||||
////////////////
|
||||
/** */
|
||||
<error descr="Statement must be prepended with case label">System.out.println();</error>
|
||||
<error descr="Statement must be prepended with a case label">System.out.println();</error>
|
||||
}
|
||||
|
||||
switch (0) {
|
||||
<error descr="Statement must be prepended with case label">break;</error>
|
||||
<error descr="Statement must be prepended with a case label">break;</error>
|
||||
}
|
||||
|
||||
switch (0) {
|
||||
<error descr="Statement must be prepended with case label">return;</error>
|
||||
<error descr="Statement must be prepended with a case label">return;</error>
|
||||
}
|
||||
|
||||
switch (0) {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ class EnhancedSwitchStatements {
|
||||
|
||||
switch (new Random().nextInt()) {
|
||||
case 0 -> throw new IllegalStateException("no args");
|
||||
<error descr="Statement must be prepended with case label">break;</error>
|
||||
<error descr="Statement must be prepended with a case label">break;</error>
|
||||
}
|
||||
switch (new Random().nextInt()) {
|
||||
case 0 -> throw new IllegalStateException("no args");
|
||||
|
||||
+2
-2
@@ -10,9 +10,9 @@ class SwitchExpressions {
|
||||
|
||||
System.out.println(switch (<error descr="'switch' expression does not have any case clauses">new Random().nextInt()</error>) { });
|
||||
|
||||
System.out.println(switch (new Random().nextInt()) {
|
||||
System.out.println(switch (<error descr="'switch' expression does not cover all possible input values">new Random().nextInt()</error>) {
|
||||
case 0 -> throw new IllegalStateException("no args");
|
||||
<error descr="Different 'case' kinds used in 'switch'">case 1:</error> yield "lone";
|
||||
case 1: yield "lone";
|
||||
});
|
||||
|
||||
System.out.println(
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ class C {
|
||||
public static void main(String[] args) {
|
||||
switch (args.length) {
|
||||
|
||||
<error descr="Statement must be prepended with case label">return;</error>
|
||||
<error descr="Statement must be prepended with a case label">return;</error>
|
||||
case 1:
|
||||
System.out.println("");
|
||||
System.out.println("");
|
||||
|
||||
Reference in New Issue
Block a user