[java-highlighting] checkResourceVariableIsFinal migrated

Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only)

GitOrigin-RevId: 2a786e61d8da816b6f85fa8ca8d4d0d1cdbab393
This commit is contained in:
Tagir Valeev
2025-02-06 10:35:32 +00:00
committed by intellij-monorepo-bot
parent 7e1d0f2784
commit c27cd7c481
6 changed files with 33 additions and 34 deletions
@@ -377,6 +377,7 @@ pattern.instanceof.supertype=Pattern type ''{0}'' is a supertype of expression t
pattern.instanceof.equals=Pattern type ''{0}'' is the same as expression type
variable.must.be.final=Variable ''{0}'' is accessed from within inner class, needs to be declared final
variable.must.be.final.resource=Variable used as a try-with-resources resource should be final or effectively final
variable.must.be.effectively.final=Variable ''{0}'' is accessed from within inner class, needs to be final or effectively final
variable.must.be.effectively.final.lambda=Variable used in lambda expression should be final or effectively final
variable.must.be.effectively.final.guard=Variable used in guard expression should be final or effectively final
@@ -411,6 +412,8 @@ expression.qualified.class.expected=Class name expected here
expression.class.type.parameter=Cannot access class object of a type parameter
expression.class.parameterized.type=Cannot access class object of parameterized type
resource.declaration.or.variable.expected=Declaration, final or effectively final variable expected
assignment.declared.outside.guard=Cannot assign a value to variable ''{0}'', because it is declared outside the guard
assignment.to.final.variable=Cannot assign a value to final variable ''{0}''
lvalue.variable.expected=Variable expected
@@ -11,6 +11,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.pom.java.JavaFeature;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
@@ -788,6 +789,29 @@ final class ExpressionChecker {
}
}
void checkResourceVariableIsFinal(@NotNull PsiResourceExpression resource) {
PsiExpression expression = resource.getExpression();
if (expression instanceof PsiThisExpression) return;
if (expression instanceof PsiReferenceExpression ref) {
PsiElement target = ref.resolve();
if (target == null) return;
if (target instanceof PsiVariable variable) {
PsiModifierList modifierList = variable.getModifierList();
if (modifierList != null && modifierList.hasModifierProperty(PsiModifier.FINAL)) return;
if (!(variable instanceof PsiField) && ControlFlowUtil.isEffectivelyFinal(variable, resource)) return;
}
myVisitor.report(JavaErrorKinds.VARIABLE_MUST_BE_FINAL_RESOURCE.create(ref));
return;
}
myVisitor.report(JavaErrorKinds.RESOURCE_DECLARATION_OR_VARIABLE_EXPECTED.create(expression));
}
private static boolean isIntersection(@NotNull PsiTypeElement castTypeElement, @NotNull PsiType castType) {
if (castType instanceof PsiIntersectionType) return true;
return castType instanceof PsiClassType && PsiTreeUtil.getChildrenOfType(castTypeElement, PsiTypeElement.class) != null;
@@ -654,6 +654,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (!hasErrorResults()) checkFeature(resource, JavaFeature.REFS_AS_RESOURCE);
if (!hasErrorResults()) myStatementChecker.checkTryResourceIsAutoCloseable(resource);
if (!hasErrorResults()) myExpressionChecker.checkUnhandledCloserExceptions(resource);
if (!hasErrorResults()) myExpressionChecker.checkResourceVariableIsFinal(resource);
}
@@ -853,6 +853,9 @@ public final class JavaErrorKinds {
requireNonNull(ctx.type1()).getPresentableText(),
requireNonNull(ctx.type2()).getPresentableText()));
public static final Simple<PsiExpression> RESOURCE_DECLARATION_OR_VARIABLE_EXPECTED =
error("resource.declaration.or.variable.expected");
public static final Simple<PsiReferenceExpression> EXPRESSION_EXPECTED = error("expression.expected");
public static final Parameterized<PsiReferenceExpression, PsiSuperExpression> EXPRESSION_SUPER_UNQUALIFIED_DEFAULT_METHOD =
parameterized("expression.super.unqualified.default.method");
@@ -1288,6 +1291,8 @@ public final class JavaErrorKinds {
public static final Parameterized<PsiJavaCodeReferenceElement, PsiVariable> VARIABLE_MUST_BE_FINAL =
parameterized(PsiJavaCodeReferenceElement.class, PsiVariable.class, "variable.must.be.final")
.withRawDescription((ref, var) -> message("variable.must.be.final", var.getName()));
public static final Simple<PsiReferenceExpression> VARIABLE_MUST_BE_FINAL_RESOURCE =
error(PsiReferenceExpression.class, "variable.must.be.final.resource");
public static final Parameterized<PsiJavaCodeReferenceElement, PsiVariable> VARIABLE_MUST_BE_EFFECTIVELY_FINAL =
parameterized(PsiJavaCodeReferenceElement.class, PsiVariable.class, "variable.must.be.effectively.final")
.withRawDescription((ref, var) -> message("variable.must.be.effectively.final", var.getName()));
@@ -28,7 +28,6 @@ import com.intellij.openapi.util.text.HtmlChunk;
import com.intellij.pom.java.JavaFeature;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.search.GlobalSearchScope;
@@ -257,33 +256,6 @@ public final class HighlightUtil {
return container == null ? "?" : HighlightMessageUtil.getSymbolName(container, substitutor);
}
static HighlightInfo.Builder checkResourceVariableIsFinal(@NotNull PsiResourceExpression resource) {
PsiExpression expression = resource.getExpression();
if (expression instanceof PsiThisExpression) return null;
if (expression instanceof PsiReferenceExpression ref) {
PsiElement target = ref.resolve();
if (target == null) return null;
if (target instanceof PsiVariable variable) {
PsiModifierList modifierList = variable.getModifierList();
if (modifierList != null && modifierList.hasModifierProperty(PsiModifier.FINAL)) return null;
if (!(variable instanceof PsiField) && ControlFlowUtil.isEffectivelyFinal(variable, resource)) {
return null;
}
}
String text = JavaErrorBundle.message("resource.variable.must.be.final");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(text);
}
String text = JavaErrorBundle.message("declaration.or.variable.expected");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(text);
}
static void checkSwitchExpressionHasResult(@NotNull PsiSwitchExpression switchExpression,
@NotNull Consumer<? super HighlightInfo.Builder> errorSink) {
PsiCodeBlock switchBody = switchExpression.getBody();
@@ -489,12 +489,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!hasErrorResults()) model.checkSwitchLabelValues(myErrorSink);
}
@Override
public void visitResourceExpression(@NotNull PsiResourceExpression resource) {
super.visitResourceExpression(resource);
if (!hasErrorResults()) add(HighlightUtil.checkResourceVariableIsFinal(resource));
}
@Override
public void visitTypeElement(@NotNull PsiTypeElement type) {
super.visitTypeElement(type);