mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
[java-inspections] checkNotAStatement -> StatementChecker
Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: 9450280ccdb333167828b22238d4a7ebf95de3c2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9dbf2ace73
commit
4c3dca5425
@@ -218,6 +218,8 @@ reference.implicit.class=Implicitly declared class ''{0}'' cannot be referenced
|
||||
|
||||
statement.case.outside.switch=Case statement outside switch
|
||||
statement.invalid=Invalid statement
|
||||
statement.declaration.not.allowed=Declaration not allowed here
|
||||
statement.bad.expression=Not a statement
|
||||
|
||||
guard.misplaced=Guard is allowed after patterns only
|
||||
guard.evaluated.to.false=This case label has a guard that is a constant expression with value 'false'
|
||||
|
||||
@@ -110,6 +110,12 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
if (!hasErrorResults()) myRecordChecker.checkRecordAccessorReturnType(recordComponent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStatement(@NotNull PsiStatement statement) {
|
||||
super.visitStatement(statement);
|
||||
if (!hasErrorResults()) myStatementChecker.checkNotAStatement(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryStatement(@NotNull PsiTryStatement statement) {
|
||||
super.visitTryStatement(statement);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.java.codeserver.highlighting;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
@@ -271,4 +272,26 @@ final class StatementChecker {
|
||||
myVisitor.report(JavaErrorKinds.RETURN_VALUE_MISSING.create(statement, method));
|
||||
}
|
||||
}
|
||||
|
||||
void checkNotAStatement(@NotNull PsiStatement statement) {
|
||||
if (PsiUtil.isStatement(statement)) return;
|
||||
if (PsiUtilCore.hasErrorElementChild(statement)) {
|
||||
boolean allowedError = false;
|
||||
if (statement instanceof PsiExpressionStatement) {
|
||||
PsiElement[] children = statement.getChildren();
|
||||
if (children[0] instanceof PsiExpression && children[1] instanceof PsiErrorElement errorElement &&
|
||||
errorElement.getErrorDescription().equals(JavaPsiBundle.message("expected.semicolon"))) {
|
||||
allowedError = true;
|
||||
}
|
||||
}
|
||||
if (!allowedError) return;
|
||||
}
|
||||
boolean isDeclarationNotAllowed = false;
|
||||
if (statement instanceof PsiDeclarationStatement) {
|
||||
PsiElement parent = statement.getParent();
|
||||
isDeclarationNotAllowed = parent instanceof PsiIfStatement || parent instanceof PsiLoopStatement;
|
||||
}
|
||||
var kind = isDeclarationNotAllowed ? JavaErrorKinds.STATEMENT_DECLARATION_NOT_ALLOWED : JavaErrorKinds.STATEMENT_BAD_EXPRESSION;
|
||||
myVisitor.report(kind.create(statement));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -765,6 +765,8 @@ public final class JavaErrorKinds {
|
||||
|
||||
public static final Simple<PsiSwitchLabelStatementBase> STATEMENT_CASE_OUTSIDE_SWITCH = error("statement.case.outside.switch");
|
||||
public static final Simple<PsiStatement> STATEMENT_INVALID = error("statement.invalid");
|
||||
public static final Simple<PsiStatement> STATEMENT_BAD_EXPRESSION = error("statement.bad.expression");
|
||||
public static final Simple<PsiStatement> STATEMENT_DECLARATION_NOT_ALLOWED = error("statement.declaration.not.allowed");
|
||||
|
||||
public static final Simple<PsiExpression> GUARD_MISPLACED = error("guard.misplaced");
|
||||
public static final Simple<PsiExpression> GUARD_EVALUATED_TO_FALSE = error("guard.evaluated.to.false");
|
||||
|
||||
@@ -388,7 +388,7 @@ public final class HighlightFixUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerFixesForExpressionStatement(@NotNull PsiElement statement, @NotNull List<? super IntentionAction> registrar) {
|
||||
public static void registerFixesForExpressionStatement(@NotNull PsiElement statement, @NotNull Consumer<? super CommonIntentionAction> info) {
|
||||
if (!(statement instanceof PsiExpressionStatement)) return;
|
||||
PsiCodeBlock block = ObjectUtils.tryCast(statement.getParent(), PsiCodeBlock.class);
|
||||
if (block == null) return;
|
||||
@@ -397,14 +397,14 @@ public final class HighlightFixUtil {
|
||||
PsiType type = expression.getType();
|
||||
if (type == null) return;
|
||||
if (!type.equals(PsiTypes.voidType())) {
|
||||
registrar.add(PriorityIntentionActionWrapper.highPriority(QuickFixFactory.getInstance().createIterateFix(expression)));
|
||||
info.accept(PriorityIntentionActionWrapper.highPriority(QuickFixFactory.getInstance().createIterateFix(expression)));
|
||||
if (PsiTreeUtil.skipWhitespacesAndCommentsForward(statement) == block.getRBrace() && block.getParent() instanceof PsiMethod method) {
|
||||
PsiType returnType = method.getReturnType();
|
||||
if (returnType != null && isPossibleReturnValue(expression, type, returnType)) {
|
||||
registrar.add(QuickFixFactory.getInstance().createInsertReturnFix(expression));
|
||||
info.accept(QuickFixFactory.getInstance().createInsertReturnFix(expression));
|
||||
}
|
||||
}
|
||||
registrar.add(QuickFixFactory.getInstance().createIntroduceVariableAction(expression));
|
||||
info.accept(QuickFixFactory.getInstance().createIntroduceVariableAction(expression));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,8 @@ import com.intellij.codeInsight.highlighting.HighlightUsagesDescriptionLocation;
|
||||
import com.intellij.codeInsight.intention.CommonIntentionAction;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper;
|
||||
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixUpdater;
|
||||
import com.intellij.codeInspection.dataFlow.fix.RedundantInstanceofFix;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.modcommand.ModCommandAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -634,47 +632,6 @@ public final class HighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkNotAStatement(@NotNull PsiStatement statement) {
|
||||
if (PsiUtil.isStatement(statement)) {
|
||||
return null;
|
||||
}
|
||||
PsiElement anchor = statement;
|
||||
if (PsiUtilCore.hasErrorElementChild(statement)) {
|
||||
boolean allowedError = false;
|
||||
if (statement instanceof PsiExpressionStatement) {
|
||||
PsiElement[] children = statement.getChildren();
|
||||
if (children[0] instanceof PsiExpression && children[1] instanceof PsiErrorElement errorElement &&
|
||||
errorElement.getErrorDescription().equals(JavaPsiBundle.message("expected.semicolon"))) {
|
||||
allowedError = true;
|
||||
anchor = children[0];
|
||||
}
|
||||
}
|
||||
if (!allowedError) return null;
|
||||
}
|
||||
boolean isDeclarationNotAllowed = false;
|
||||
if (statement instanceof PsiDeclarationStatement) {
|
||||
PsiElement parent = statement.getParent();
|
||||
isDeclarationNotAllowed = parent instanceof PsiIfStatement || parent instanceof PsiLoopStatement;
|
||||
}
|
||||
String description = JavaErrorBundle.message(isDeclarationNotAllowed ? "declaration.not.allowed" : "not.a.statement");
|
||||
HighlightInfo.Builder error =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(anchor).descriptionAndTooltip(description);
|
||||
if (statement instanceof PsiExpressionStatement expressionStatement) {
|
||||
List<IntentionAction> registrar = new ArrayList<>();
|
||||
HighlightFixUtil.registerFixesForExpressionStatement(statement, registrar);
|
||||
QuickFixAction.registerQuickFixActions(error, null, registrar);
|
||||
PsiElement parent = expressionStatement.getParent();
|
||||
if (parent instanceof PsiCodeBlock ||
|
||||
parent instanceof PsiIfStatement ||
|
||||
parent instanceof PsiLoopStatement loop && loop.getBody() == expressionStatement) {
|
||||
IntentionAction action = PriorityIntentionActionWrapper
|
||||
.lowPriority(getFixFactory().createDeleteSideEffectAwareFix(expressionStatement));
|
||||
error.registerFix(action, null, null, null, null);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void checkSwitchExpressionReturnTypeCompatible(@NotNull PsiSwitchExpression switchExpression,
|
||||
@NotNull Consumer<? super HighlightInfo.Builder> errorSink) {
|
||||
if (!PsiPolyExpressionUtil.isPolyExpression(switchExpression)) {
|
||||
|
||||
@@ -1132,12 +1132,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (!hasErrorResults()) add(GenericsHighlightUtil.checkParametersOnRaw(list, myLanguageLevel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStatement(@NotNull PsiStatement statement) {
|
||||
super.visitStatement(statement);
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkNotAStatement(statement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitchStatement(@NotNull PsiSwitchStatement statement) {
|
||||
super.visitSwitchStatement(statement);
|
||||
|
||||
@@ -147,6 +147,17 @@ final class JavaErrorFixProvider {
|
||||
};
|
||||
fixes(RETURN_FROM_CONSTRUCTOR, fixReturnFromVoid);
|
||||
fixes(RETURN_FROM_VOID_METHOD, fixReturnFromVoid);
|
||||
fixes(STATEMENT_BAD_EXPRESSION, (error, sink) -> {
|
||||
if (error.psi() instanceof PsiExpressionStatement expressionStatement) {
|
||||
HighlightFixUtil.registerFixesForExpressionStatement(expressionStatement, sink);
|
||||
PsiElement parent = expressionStatement.getParent();
|
||||
if (parent instanceof PsiCodeBlock ||
|
||||
parent instanceof PsiIfStatement ||
|
||||
parent instanceof PsiLoopStatement loop && loop.getBody() == expressionStatement) {
|
||||
sink.accept(PriorityIntentionActionWrapper.lowPriority(myFactory.createDeleteSideEffectAwareFix(expressionStatement)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createMethodFixes() {
|
||||
|
||||
@@ -27,7 +27,7 @@ public final class JavaErrorQuickFixProvider implements ErrorQuickFixProvider, D
|
||||
List<IntentionAction> registrar = new ArrayList<>();
|
||||
if (description.equals(JavaPsiBundle.message("expected.semicolon"))) {
|
||||
info.registerFix(new InsertMissingTokenFix(";"), null, null, null, null);
|
||||
HighlightFixUtil.registerFixesForExpressionStatement(parent, registrar);
|
||||
HighlightFixUtil.registerFixesForExpressionStatement(parent, action -> registrar.add(action.asIntention()));
|
||||
}
|
||||
if (parent instanceof PsiTryStatement && description.equals(JavaPsiBundle.message("expected.catch.or.finally"))) {
|
||||
registrar.add(new AddExceptionToCatchFix(false).asIntention());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class C {
|
||||
void foo(int i, int j) {
|
||||
<error descr="Not a statement">123</error>
|
||||
<error descr="Not a statement">i+j</error> /*oops*/
|
||||
<error descr="Not a statement">i+j /*oops*/</error>
|
||||
foo(1, 2)<EOLError descr="';' expected"></EOLError>
|
||||
i++<EOLError descr="';' expected"></EOLError>
|
||||
toString()<error descr="';' expected"> </error>/*oops*/
|
||||
|
||||
@@ -20,7 +20,7 @@ class TryWithResources {
|
||||
|
||||
void testType() throws Exception {
|
||||
String s = "";
|
||||
try (<error descr="Incompatible types. Found: 'java.lang.String', required: 'java.lang.AutoCloseable'">s</error>;
|
||||
try (<error descr="Incompatible types. Found: 'java.lang.String', required: 'java.lang.AutoCloseable'">s;</error>
|
||||
<error descr="Incompatible types. Found: 'TryWithResources', required: 'java.lang.AutoCloseable'">this</error>) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class Test {
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
void testNested(Object o, Integer in) {
|
||||
void testNested(Object o, Integer in, AutoCloseable in1) {
|
||||
switch (o) {
|
||||
case Integer mode when (<error descr="Cannot assign a value to variable 'mode', because it is declared outside the guard">mode</error> = 42) > 9:
|
||||
switch (o) {
|
||||
@@ -97,9 +97,9 @@ class Test {
|
||||
<error descr="Variable used in lambda expression should be final or effectively final">in</error> = 1;
|
||||
};
|
||||
// try-with-resources
|
||||
try (<error descr="Variable used as a try-with-resources resource should be final or effectively final">in</error>) {
|
||||
try (<error descr="Variable used as a try-with-resources resource should be final or effectively final">in1</error>) {
|
||||
switch (o) {
|
||||
case AutoCloseable ii when (<error descr="Cannot assign a value to variable 'in', because it is declared outside the guard">in</error> = 1) != null: break;
|
||||
case AutoCloseable ii when (<error descr="Cannot assign a value to variable 'in1', because it is declared outside the guard">in1</error> = ii) != null: break;
|
||||
default: break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user