mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] checkVariableMustBeFinal migrated
Also: intermediate refactoring inside HighlightControlFlowUtil related to init-before-use Also: ErrorFixExtensionPoint now works for any kind (intermediate solution) Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: 7a712a841a52a99bac4faafaf1164921c1150a56
This commit is contained in:
committed by
intellij-monorepo-bot
parent
32eeb4ee9f
commit
913cade2a5
@@ -374,6 +374,11 @@ pattern.cannot.infer.type=Cannot infer pattern type: {0}
|
||||
pattern.instanceof.supertype=Pattern type ''{0}'' is a supertype of expression type ''{1}''
|
||||
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.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
|
||||
|
||||
instanceof.type.parameter=Class or array expected
|
||||
instanceof.illegal.generic.type=Illegal generic type for instanceof
|
||||
instanceof.unsafe.cast=''{0}'' cannot be safely cast to ''{1}''
|
||||
|
||||
+29
@@ -3,6 +3,7 @@ package com.intellij.java.codeserver.highlighting;
|
||||
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
@@ -94,6 +95,34 @@ final class ControlFlowChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkVariableMustBeFinal(@NotNull PsiVariable variable, @NotNull PsiJavaCodeReferenceElement context) {
|
||||
if (variable.hasModifierProperty(PsiModifier.FINAL)) return;
|
||||
PsiElement scope = ControlFlowUtil.getScopeEnforcingEffectiveFinality(variable, context);
|
||||
if (scope == null) return;
|
||||
if (scope instanceof PsiClass) {
|
||||
if (variable instanceof PsiParameter parameter) {
|
||||
PsiElement parent = variable.getParent();
|
||||
if (parent instanceof PsiParameterList && parent.getParent() instanceof PsiLambdaExpression &&
|
||||
ControlFlowUtil.isEffectivelyFinal(variable, parameter.getDeclarationScope())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
boolean isToBeEffectivelyFinal = myVisitor.isApplicable(JavaFeature.EFFECTIVELY_FINAL);
|
||||
if (isToBeEffectivelyFinal && ControlFlowUtil.isEffectivelyFinal(variable, scope, context)) return;
|
||||
var kind = isToBeEffectivelyFinal ? JavaErrorKinds.VARIABLE_MUST_BE_EFFECTIVELY_FINAL : JavaErrorKinds.VARIABLE_MUST_BE_FINAL;
|
||||
myVisitor.report(kind.create(context, variable));
|
||||
return;
|
||||
} else if (scope instanceof PsiLambdaExpression) {
|
||||
if (ControlFlowUtil.isEffectivelyFinal(variable, scope, context)) return;
|
||||
myVisitor.report(JavaErrorKinds.VARIABLE_MUST_BE_EFFECTIVELY_FINAL_LAMBDA.create(context, variable));
|
||||
} else if (scope instanceof PsiSwitchLabelStatementBase) {
|
||||
// Reported separately in ExpressionChecker.checkOutsideDeclaredCantBeAssignmentInGuard
|
||||
if (context instanceof PsiReferenceExpression ref && PsiUtil.isAccessedForWriting(ref)) return;
|
||||
if (ControlFlowUtil.isEffectivelyFinal(variable, scope, context)) return;
|
||||
myVisitor.report(JavaErrorKinds.VARIABLE_MUST_BE_EFFECTIVELY_FINAL_GUARD.create(context, variable));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return field that has initializer with this element as subexpression or null if not found
|
||||
*/
|
||||
|
||||
+4
-1
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Objects.*;
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
|
||||
final class ExpressionChecker {
|
||||
private final @NotNull JavaErrorVisitor myVisitor;
|
||||
@@ -919,6 +919,9 @@ final class ExpressionChecker {
|
||||
!PsiUtil.isFromDefaultPackage(myVisitor.file()))) {
|
||||
myVisitor.report(JavaErrorKinds.REFERENCE_CLASS_IN_DEFAULT_PACKAGE.create(ref, psiClass));
|
||||
}
|
||||
if ((resolved instanceof PsiLocalVariable || resolved instanceof PsiParameter) && !(resolved instanceof ImplicitVariable)) {
|
||||
myVisitor.myControlFlowChecker.checkVariableMustBeFinal((PsiVariable)resolved, ref);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean favorParentReport(@NotNull PsiCall methodCall, @NotNull String errorMessage) {
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
final @NotNull TypeChecker myTypeChecker = new TypeChecker(this);
|
||||
final @NotNull MethodChecker myMethodChecker = new MethodChecker(this);
|
||||
private final @NotNull ReceiverChecker myReceiverChecker = new ReceiverChecker(this);
|
||||
private final @NotNull ControlFlowChecker myControlFlowChecker = new ControlFlowChecker(this);
|
||||
final @NotNull ControlFlowChecker myControlFlowChecker = new ControlFlowChecker(this);
|
||||
private final @NotNull FunctionChecker myFunctionChecker = new FunctionChecker(this);
|
||||
final @NotNull PatternChecker myPatternChecker = new PatternChecker(this);
|
||||
final @NotNull ModifierChecker myModifierChecker = new ModifierChecker(this);
|
||||
|
||||
+11
@@ -1235,6 +1235,17 @@ public final class JavaErrorKinds {
|
||||
public static final Parameterized<PsiReturnStatement, PsiMethodCallExpression> RETURN_BEFORE_EXPLICIT_CONSTRUCTOR_CALL =
|
||||
parameterized(PsiReturnStatement.class, PsiMethodCallExpression.class, "return.before.explicit.constructor.call")
|
||||
.withRawDescription((psi, call) -> message("return.before.explicit.constructor.call", call.getMethodExpression().getText() + "()"));
|
||||
|
||||
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 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()));
|
||||
public static final Parameterized<PsiJavaCodeReferenceElement, PsiVariable> VARIABLE_MUST_BE_EFFECTIVELY_FINAL_LAMBDA =
|
||||
parameterized(PsiJavaCodeReferenceElement.class, PsiVariable.class, "variable.must.be.effectively.final.lambda");
|
||||
public static final Parameterized<PsiJavaCodeReferenceElement, PsiVariable> VARIABLE_MUST_BE_EFFECTIVELY_FINAL_GUARD =
|
||||
parameterized(PsiJavaCodeReferenceElement.class, PsiVariable.class, "variable.must.be.effectively.final.guard");
|
||||
|
||||
private static @NotNull <Psi extends PsiElement> Simple<Psi> error(
|
||||
@NotNull @PropertyKey(resourceBundle = JavaCompilationErrorBundle.BUNDLE) String key) {
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.intention.CommonIntentionAction;
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.java.codeserver.highlighting.JavaCompilationErrorBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.PluginAware;
|
||||
@@ -27,6 +28,7 @@ public final class ErrorFixExtensionPoint implements PluginAware {
|
||||
new ExtensionPointName<>("com.intellij.java.error.fix");
|
||||
|
||||
@Attribute("errorCode")
|
||||
@PropertyKey(resourceBundle = JavaCompilationErrorBundle.BUNDLE)
|
||||
public String errorCode;
|
||||
|
||||
@Attribute("implementationClass")
|
||||
|
||||
+71
-154
@@ -14,8 +14,6 @@ import com.intellij.lang.jvm.actions.MemberRequestsKt;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.util.Predicates;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
@@ -26,10 +24,8 @@ import com.intellij.psi.util.*;
|
||||
import com.intellij.util.JavaPsiConstructorUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.VariableAccessUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
@@ -217,78 +213,65 @@ public final class HighlightControlFlowUtil {
|
||||
}
|
||||
|
||||
|
||||
public static HighlightInfo.Builder checkVariableInitializedBeforeUsage(@NotNull PsiReferenceExpression expression,
|
||||
@NotNull PsiVariable variable,
|
||||
@NotNull Map<? super PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems,
|
||||
@NotNull PsiFile containingFile) {
|
||||
return checkVariableInitializedBeforeUsage(expression, variable, uninitializedVarProblems, containingFile, false);
|
||||
static HighlightInfo.Builder checkVariableInitializedBeforeUsage(@NotNull PsiReferenceExpression expression,
|
||||
@NotNull PsiVariable variable,
|
||||
@NotNull Map<? super PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems) {
|
||||
if (isInitializedBeforeUsage(expression, variable, uninitializedVarProblems, false)) return null;
|
||||
return createNotInitializedError(expression, variable);
|
||||
}
|
||||
|
||||
public static HighlightInfo.Builder checkVariableInitializedBeforeUsage(@NotNull PsiReferenceExpression expression,
|
||||
@NotNull PsiVariable variable,
|
||||
@NotNull Map<? super PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems,
|
||||
@NotNull PsiFile containingFile,
|
||||
boolean ignoreFinality) {
|
||||
if (variable instanceof ImplicitVariable) return null;
|
||||
if (!PsiUtil.isAccessedForReading(expression)) return null;
|
||||
public static boolean isInitializedBeforeUsage(@NotNull PsiReferenceExpression expression,
|
||||
@NotNull PsiVariable variable,
|
||||
@NotNull Map<? super PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems,
|
||||
boolean ignoreFinality) {
|
||||
if (variable instanceof ImplicitVariable) return true;
|
||||
if (!PsiUtil.isAccessedForReading(expression)) return true;
|
||||
int startOffset = expression.getTextRange().getStartOffset();
|
||||
PsiElement topBlock;
|
||||
if (variable.hasInitializer()) {
|
||||
topBlock = PsiUtil.getVariableCodeBlock(variable, variable);
|
||||
if (topBlock == null) return null;
|
||||
}
|
||||
else {
|
||||
PsiElement scope = variable instanceof PsiField field
|
||||
? field.getContainingClass()
|
||||
: variable.getParent() != null ? variable.getParent().getParent() : null;
|
||||
while (scope instanceof PsiCodeBlock && scope.getParent() instanceof PsiSwitchBlock) {
|
||||
scope = PsiTreeUtil.getParentOfType(scope, PsiCodeBlock.class);
|
||||
}
|
||||
|
||||
topBlock = FileTypeUtils.isInServerPageFile(scope) && scope instanceof PsiFile ? scope : PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope);
|
||||
PsiElement topBlock = getTopBlock(expression, variable);
|
||||
if (topBlock == null) return true;
|
||||
if (!variable.hasInitializer()) {
|
||||
if (variable instanceof PsiField field) {
|
||||
// non-final field already initialized with default value
|
||||
if (!ignoreFinality && !variable.hasModifierProperty(PsiModifier.FINAL)) return null;
|
||||
if (!ignoreFinality && !variable.hasModifierProperty(PsiModifier.FINAL)) return true;
|
||||
// a final field may be initialized in ctor or class initializer only
|
||||
// if we're inside non-ctr method, skip it
|
||||
if (PsiUtil.findEnclosingConstructorOrInitializer(expression) == null
|
||||
&& findEnclosingFieldInitializer(expression) == null) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
if (topBlock == null) return null;
|
||||
PsiElement parent = topBlock.getParent();
|
||||
// access to final fields from inner classes always allowed
|
||||
if (inInnerClass(expression, field.getContainingClass())) return null;
|
||||
if (inInnerClass(expression, field.getContainingClass())) return true;
|
||||
PsiCodeBlock block;
|
||||
PsiClass aClass;
|
||||
if (parent instanceof PsiMethod constructor) {
|
||||
if (!containingFile.getManager().areElementsEquivalent(constructor.getContainingClass(), field.getContainingClass())) return null;
|
||||
if (!constructor.getManager().areElementsEquivalent(constructor.getContainingClass(), field.getContainingClass())) return true;
|
||||
// static variables already initialized in class initializers
|
||||
if (variable.hasModifierProperty(PsiModifier.STATIC)) return null;
|
||||
if (variable.hasModifierProperty(PsiModifier.STATIC)) return true;
|
||||
// as a last chance, field may be initialized in this() call
|
||||
for (PsiMethod redirectedConstructor : JavaPsiConstructorUtil.getChainedConstructors(constructor)) {
|
||||
// variable must be initialized before its usage
|
||||
//???
|
||||
//if (startOffset < redirectedConstructor.getTextRange().getStartOffset()) continue;
|
||||
if (JavaPsiRecordUtil.isCompactConstructor(redirectedConstructor)) return null;
|
||||
if (JavaPsiRecordUtil.isCompactConstructor(redirectedConstructor)) return true;
|
||||
PsiCodeBlock body = redirectedConstructor.getBody();
|
||||
if (body != null && variableDefinitelyAssignedIn(variable, body, true)) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
block = constructor.getBody();
|
||||
aClass = constructor.getContainingClass();
|
||||
}
|
||||
else if (parent instanceof PsiClassInitializer classInitializer) {
|
||||
if (!containingFile.getManager().areElementsEquivalent(classInitializer.getContainingClass(), field.getContainingClass())) {
|
||||
return null;
|
||||
if (!classInitializer.getManager().areElementsEquivalent(classInitializer.getContainingClass(), field.getContainingClass())) {
|
||||
return true;
|
||||
}
|
||||
block = classInitializer.getBody();
|
||||
aClass = classInitializer.getContainingClass();
|
||||
|
||||
if (aClass == null || isFieldInitializedInOtherFieldInitializer(aClass, field, variable.hasModifierProperty(PsiModifier.STATIC),
|
||||
f -> startOffset > f.getTextOffset())) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -299,16 +282,16 @@ public final class HighlightControlFlowUtil {
|
||||
if (aClass == null ||
|
||||
isFieldInitializedInOtherFieldInitializer(aClass, field, field.hasModifierProperty(PsiModifier.STATIC),
|
||||
f -> f != anotherField && startOffset > f.getTextOffset())) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
if (anotherField != null
|
||||
&& !anotherField.hasModifierProperty(PsiModifier.STATIC)
|
||||
&& field.hasModifierProperty(PsiModifier.STATIC)
|
||||
&& isFieldInitializedInClassInitializer(field, true, aClass.getInitializers())) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
if (anotherField != null && anotherField.hasInitializer() && !PsiAugmentProvider.canTrustFieldInitializer(anotherField)) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
|
||||
int offset = startOffset;
|
||||
@@ -322,7 +305,7 @@ public final class HighlightControlFlowUtil {
|
||||
if (offset < constructor.getTextRange().getStartOffset()) continue;
|
||||
PsiCodeBlock body = constructor.getBody();
|
||||
if (body != null && variableDefinitelyAssignedIn(variable, body)) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
// as a last chance, field may be initialized in this() call
|
||||
for (PsiMethod redirectedConstructor : JavaPsiConstructorUtil.getChainedConstructors(constructor)) {
|
||||
@@ -330,7 +313,7 @@ public final class HighlightControlFlowUtil {
|
||||
if (offset < redirectedConstructor.getTextRange().getStartOffset()) continue;
|
||||
PsiCodeBlock redirectedBody = redirectedConstructor.getBody();
|
||||
if (redirectedBody != null && variableDefinitelyAssignedIn(variable, redirectedBody)) {
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,13 +329,12 @@ public final class HighlightControlFlowUtil {
|
||||
boolean shouldCheckInitializerOrder = block == null || block.getParent() instanceof PsiClassInitializer;
|
||||
if (shouldCheckInitializerOrder && startOffset < initializer.getTextRange().getStartOffset()) continue;
|
||||
if (initializer.hasModifierProperty(PsiModifier.STATIC) == variable.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
if (variableDefinitelyAssignedIn(variable, body)) return null;
|
||||
if (variableDefinitelyAssignedIn(variable, body)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (topBlock == null) return null;
|
||||
Collection<PsiReferenceExpression> codeBlockProblems = uninitializedVarProblems.get(topBlock);
|
||||
if (codeBlockProblems == null) {
|
||||
try {
|
||||
@@ -364,29 +346,54 @@ public final class HighlightControlFlowUtil {
|
||||
}
|
||||
uninitializedVarProblems.put(topBlock, codeBlockProblems);
|
||||
}
|
||||
if (codeBlockProblems.contains(expression)) {
|
||||
String name = expression.getElement().getText();
|
||||
String description = JavaErrorBundle.message("variable.not.initialized", name);
|
||||
HighlightInfo.Builder builder =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description);
|
||||
if (!(variable instanceof LightRecordField)) {
|
||||
IntentionAction action1 = getQuickFixFactory().createAddVariableInitializerFix(variable);
|
||||
builder.registerFix(action1, null, null, null, null);
|
||||
return !codeBlockProblems.contains(expression);
|
||||
}
|
||||
|
||||
private static @Nullable PsiElement getTopBlock(@NotNull PsiReferenceExpression expression, @NotNull PsiVariable variable) {
|
||||
PsiElement topBlock;
|
||||
if (variable.hasInitializer()) {
|
||||
topBlock = PsiUtil.getVariableCodeBlock(variable, variable);
|
||||
if (topBlock == null) return null;
|
||||
}
|
||||
else {
|
||||
PsiElement scope = variable instanceof PsiField field
|
||||
? field.getContainingClass()
|
||||
: variable.getParent() != null ? variable.getParent().getParent() : null;
|
||||
while (scope instanceof PsiCodeBlock && scope.getParent() instanceof PsiSwitchBlock) {
|
||||
scope = PsiTreeUtil.getParentOfType(scope, PsiCodeBlock.class);
|
||||
}
|
||||
if (variable instanceof PsiLocalVariable) {
|
||||
|
||||
topBlock = FileTypeUtils.isInServerPageFile(scope) && scope instanceof PsiFile
|
||||
? scope
|
||||
: PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope);
|
||||
}
|
||||
return topBlock;
|
||||
}
|
||||
|
||||
private static HighlightInfo.@NotNull Builder createNotInitializedError(@NotNull PsiReferenceExpression expression,
|
||||
@NotNull PsiVariable variable) {
|
||||
String name = expression.getElement().getText();
|
||||
String description = JavaErrorBundle.message("variable.not.initialized", name);
|
||||
HighlightInfo.Builder builder =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description);
|
||||
if (!(variable instanceof LightRecordField)) {
|
||||
IntentionAction action1 = getQuickFixFactory().createAddVariableInitializerFix(variable);
|
||||
builder.registerFix(action1, null, null, null, null);
|
||||
}
|
||||
if (variable instanceof PsiLocalVariable) {
|
||||
PsiElement topBlock = getTopBlock(expression, variable);
|
||||
if (topBlock != null) {
|
||||
IntentionAction action = HighlightFixUtil.createInsertSwitchDefaultFix(variable, topBlock, expression);
|
||||
if (action != null) {
|
||||
builder.registerFix(action, null, null, null, null);
|
||||
}
|
||||
}
|
||||
if (variable instanceof PsiField field) {
|
||||
ChangeModifierRequest request = MemberRequestsKt.modifierRequest(JvmModifier.FINAL, false);
|
||||
QuickFixAction.registerQuickFixActions(builder, null, JvmElementActionFactories.createModifierActions(field, request));
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
return null;
|
||||
if (variable instanceof PsiField field) {
|
||||
ChangeModifierRequest request = MemberRequestsKt.modifierRequest(JvmModifier.FINAL, false);
|
||||
QuickFixAction.registerQuickFixActions(builder, null, JvmElementActionFactories.createModifierActions(field, request));
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static boolean inInnerClass(@NotNull PsiElement psiElement, @Nullable PsiClass containingClass) {
|
||||
@@ -558,96 +565,6 @@ public final class HighlightControlFlowUtil {
|
||||
return codeBlockProblems;
|
||||
}
|
||||
|
||||
|
||||
static HighlightInfo.Builder checkVariableMustBeFinal(@NotNull PsiVariable variable,
|
||||
@NotNull PsiJavaCodeReferenceElement context,
|
||||
@NotNull LanguageLevel languageLevel) {
|
||||
if (variable.hasModifierProperty(PsiModifier.FINAL)) return null;
|
||||
PsiElement scope = ControlFlowUtil.getScopeEnforcingEffectiveFinality(variable, context);
|
||||
if (scope instanceof PsiClass) {
|
||||
if (variable instanceof PsiParameter parameter) {
|
||||
PsiElement parent = variable.getParent();
|
||||
if (parent instanceof PsiParameterList && parent.getParent() instanceof PsiLambdaExpression &&
|
||||
!VariableAccessUtils.variableIsAssigned(variable, parameter.getDeclarationScope())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
boolean isToBeEffectivelyFinal = JavaFeature.EFFECTIVELY_FINAL.isSufficient(languageLevel);
|
||||
if (isToBeEffectivelyFinal && ControlFlowUtil.isEffectivelyFinal(variable, scope, context)) {
|
||||
return null;
|
||||
}
|
||||
String description = JavaErrorBundle
|
||||
.message(isToBeEffectivelyFinal ? "variable.must.be.final.or.effectively.final" : "variable.must.be.final", context.getText());
|
||||
|
||||
HighlightInfo.Builder highlightInfo =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(context).descriptionAndTooltip(description);
|
||||
IntentionAction action = getQuickFixFactory().createVariableAccessFromInnerClassFix(variable, scope);
|
||||
highlightInfo.registerFix(action, null, null, null, null);
|
||||
return highlightInfo;
|
||||
}
|
||||
HighlightInfo.Builder finalInsideLambdaInfo = checkWriteToFinalInsideLambda(variable, context);
|
||||
if (finalInsideLambdaInfo != null) {
|
||||
return finalInsideLambdaInfo;
|
||||
}
|
||||
return checkFinalUsageInsideGuardedPattern(variable, context);
|
||||
}
|
||||
|
||||
private static @Nullable HighlightInfo.Builder checkWriteToFinalInsideLambda(@NotNull PsiVariable variable, @NotNull PsiJavaCodeReferenceElement context) {
|
||||
PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(context, PsiLambdaExpression.class);
|
||||
if (lambdaExpression != null && !PsiTreeUtil.isAncestor(lambdaExpression, variable, true)) {
|
||||
PsiElement parent = variable.getParent();
|
||||
if (parent instanceof PsiParameterList && parent.getParent() == lambdaExpression) {
|
||||
return null;
|
||||
}
|
||||
PsiSwitchLabelStatementBase label =
|
||||
PsiTreeUtil.getParentOfType(context, PsiSwitchLabelStatementBase.class, true, PsiLambdaExpression.class);
|
||||
if (label != null && PsiTreeUtil.isAncestor(label.getGuardExpression(), context, false)) {
|
||||
return null;
|
||||
}
|
||||
HighlightInfo.Builder builder = checkVariableMustBeEffectivelyFinal(variable, context, lambdaExpression, "lambda.variable.must.be.final");
|
||||
if (builder != null) return builder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static HighlightInfo.Builder checkVariableMustBeEffectivelyFinal(@NotNull PsiVariable variable,
|
||||
@NotNull PsiJavaCodeReferenceElement context,
|
||||
@NotNull PsiElement scope,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaErrorBundle.BUNDLE) String messageKey) {
|
||||
if (!ControlFlowUtil.isEffectivelyFinal(variable, scope, context)) {
|
||||
String text = JavaErrorBundle.message(messageKey);
|
||||
HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(context).descriptionAndTooltip(text);
|
||||
IntentionAction action1 = getQuickFixFactory().createVariableAccessFromInnerClassFix(variable, scope);
|
||||
builder.registerFix(action1, null, null, null, null);
|
||||
IntentionAction action2 = getQuickFixFactory().createMakeVariableEffectivelyFinalFix(variable);
|
||||
if (action2 != null) {
|
||||
builder.registerFix(action2, null, null, null, null);
|
||||
}
|
||||
ErrorFixExtensionPoint.registerFixes(builder, context, messageKey);
|
||||
return builder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 14.30.1 Kinds of Patterns
|
||||
* <p>Any variable that is used but not declared in the guarding expression of a guarded pattern must either be final or effectively final.
|
||||
*/
|
||||
private static @Nullable HighlightInfo.Builder checkFinalUsageInsideGuardedPattern(@NotNull PsiVariable variable, @NotNull PsiJavaCodeReferenceElement context) {
|
||||
PsiSwitchLabelStatementBase refLabel = PsiTreeUtil.getParentOfType(context, PsiSwitchLabelStatementBase.class);
|
||||
|
||||
if (refLabel == null) return null;
|
||||
PsiExpression guardExpression = refLabel.getGuardExpression();
|
||||
if (!PsiTreeUtil.isAncestor(guardExpression, context, false)) return null;
|
||||
//this assignment is covered by com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil.checkOutsideDeclaredCantBeAssignmentInGuard
|
||||
boolean isAssignment = context instanceof PsiReferenceExpression ref && PsiUtil.isAccessedForWriting(ref);
|
||||
if (!isAssignment && !PsiTreeUtil.isAncestor(guardExpression, variable, false)) {
|
||||
HighlightInfo.Builder builder = checkVariableMustBeEffectivelyFinal(variable, context, refLabel, "guarded.pattern.variable.must.be.final");
|
||||
if (builder != null) return builder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A kind of final variable problem returned from {@link #getFinalVariableProblemsInBlock(Map, PsiElement)}
|
||||
* which designates a final variable which is initialized in a loop.
|
||||
|
||||
-4
@@ -958,10 +958,6 @@ public final class HighlightUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if ((resolved instanceof PsiLocalVariable || resolved instanceof PsiParameter) && !(resolved instanceof ImplicitVariable)) {
|
||||
return HighlightControlFlowUtil.checkVariableMustBeFinal((PsiVariable)resolved, ref, languageLevel);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -5,6 +5,7 @@ import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightVisitor;
|
||||
import com.intellij.codeInsight.intention.CommonIntentionAction;
|
||||
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
|
||||
import com.intellij.codeInspection.ex.GlobalInspectionContextBase;
|
||||
import com.intellij.java.codeserver.highlighting.JavaErrorCollector;
|
||||
@@ -222,7 +223,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
} else {
|
||||
info.range(anchor);
|
||||
}
|
||||
errorFixProvider.processFixes(error, fix -> info.registerFix(fix.asIntention(), null, null, null, null));
|
||||
Consumer<@NotNull CommonIntentionAction> consumer = fix -> info.registerFix(fix.asIntention(), null, null, null, null);
|
||||
errorFixProvider.processFixes(error, consumer);
|
||||
ErrorFixExtensionPoint.registerFixes(consumer, error.psi(), error.kind().key());
|
||||
error.psiForKind(EXPRESSION_EXPECTED, REFERENCE_UNRESOLVED, REFERENCE_AMBIGUOUS)
|
||||
.or(() -> error.psiForKind(TYPE_UNKNOWN_CLASS).map(PsiTypeElement::getInnermostComponentReferenceElement))
|
||||
.or(() -> error.psiForKind(CALL_AMBIGUOUS_NO_MATCH, CALL_UNRESOLVED).map(PsiMethodCallExpression::getMethodExpression))
|
||||
@@ -490,7 +493,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
if (!hasErrorResults()) {
|
||||
try {
|
||||
add(HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, variable, myUninitializedVarProblems, myFile));
|
||||
add(HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, variable, myUninitializedVarProblems));
|
||||
}
|
||||
catch (IndexNotReadyException ignored) {
|
||||
}
|
||||
|
||||
+14
-2
@@ -47,7 +47,8 @@ import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds.*;
|
||||
import static java.util.Objects.*;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
|
||||
/**
|
||||
* Fixes attached to error messages provided by {@link JavaErrorCollector}.
|
||||
@@ -277,7 +278,6 @@ final class JavaErrorFixProvider {
|
||||
else if (element instanceof PsiClass cls) {
|
||||
sink.accept(myFactory.createCreateConstructorMatchingSuperFix(cls));
|
||||
}
|
||||
ErrorFixExtensionPoint.registerFixes(sink, element, "unhandled.exceptions");
|
||||
});
|
||||
fixes(EXCEPTION_UNHANDLED_CLOSE, (error, sink) -> HighlightFixUtil.registerUnhandledExceptionFixes(error.psi(), sink));
|
||||
}
|
||||
@@ -375,6 +375,18 @@ final class JavaErrorFixProvider {
|
||||
fix(UNNAMED_VARIABLE_WITHOUT_INITIALIZER, error -> myFactory.createAddVariableInitializerFix(error.psi()));
|
||||
fixes(LVTI_NO_INITIALIZER, (error, sink) -> HighlightFixUtil.registerSpecifyVarTypeFix(error.psi(), sink));
|
||||
fixes(LVTI_NULL, (error, sink) -> HighlightFixUtil.registerSpecifyVarTypeFix(error.psi(), sink));
|
||||
JavaFixProvider<PsiJavaCodeReferenceElement, PsiVariable> innerClassAccessFix = error -> {
|
||||
PsiVariable variable = error.context();
|
||||
PsiElement scope = requireNonNull(ControlFlowUtil.getScopeEnforcingEffectiveFinality(variable, error.psi()));
|
||||
return myFactory.createVariableAccessFromInnerClassFix(variable, scope);
|
||||
};
|
||||
fix(VARIABLE_MUST_BE_FINAL, innerClassAccessFix);
|
||||
fix(VARIABLE_MUST_BE_EFFECTIVELY_FINAL, innerClassAccessFix);
|
||||
fix(VARIABLE_MUST_BE_EFFECTIVELY_FINAL_LAMBDA, innerClassAccessFix);
|
||||
fix(VARIABLE_MUST_BE_EFFECTIVELY_FINAL_GUARD, innerClassAccessFix);
|
||||
fix(VARIABLE_MUST_BE_EFFECTIVELY_FINAL, error -> myFactory.createMakeVariableEffectivelyFinalFix(error.context()));
|
||||
fix(VARIABLE_MUST_BE_EFFECTIVELY_FINAL_LAMBDA, error -> myFactory.createMakeVariableEffectivelyFinalFix(error.context()));
|
||||
fix(VARIABLE_MUST_BE_EFFECTIVELY_FINAL_GUARD, error -> myFactory.createMakeVariableEffectivelyFinalFix(error.context()));
|
||||
}
|
||||
|
||||
private void createExpressionFixes() {
|
||||
|
||||
@@ -57,9 +57,10 @@ public final class FinalUtils {
|
||||
Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> finalVarProblems) {
|
||||
if (!(e instanceof PsiReferenceExpression ref)) return true;
|
||||
if (!ref.isReferenceTo(variable)) return true;
|
||||
HighlightInfo.Builder highlightInfo = HighlightControlFlowUtil
|
||||
.checkVariableInitializedBeforeUsage(ref, variable, uninitializedVarProblems, variable.getContainingFile(), true);
|
||||
if (highlightInfo != null) return false;
|
||||
if (!HighlightControlFlowUtil.isInitializedBeforeUsage(
|
||||
ref, variable, uninitializedVarProblems, true)) {
|
||||
return false;
|
||||
}
|
||||
if (!PsiUtil.isAccessedForWriting(ref)) return true;
|
||||
if (!LocalsOrMyInstanceFieldsControlFlowPolicy.isLocalOrMyInstanceReference(ref)) return false;
|
||||
if (ControlFlowUtil.isVariableAssignedInLoop(ref, variable)) return false;
|
||||
|
||||
@@ -939,7 +939,7 @@
|
||||
<jvm.logging implementation="com.intellij.lang.logging.UnspecifiedLogger"/>
|
||||
|
||||
<javaModuleSystem implementation="com.intellij.psi.impl.JavaPlatformModuleSystem"/>
|
||||
<java.error.fix errorCode="lambda.variable.must.be.final"
|
||||
<java.error.fix errorCode="variable.must.be.effectively.final.lambda"
|
||||
implementationClass="com.intellij.codeInspection.streamMigration.SimplifyForEachInspection$ForEachNonFinalFix"/>
|
||||
<lang.jvm.actions.jvmElementActionsFactory implementation="com.intellij.codeInsight.intention.impl.JavaElementActionsFactory"/>
|
||||
<longLineInspectionPolicy implementation="com.intellij.codeInspection.JavaLongLineInspectionPolicy"/>
|
||||
@@ -1580,9 +1580,9 @@
|
||||
<lang.namesValidator language="JAVA" implementationClass="com.intellij.lang.refactoring.JavaNamesValidator"/>
|
||||
<actionPromoter implementation="com.intellij.codeInsight.editorActions.JavaMethodOverloadSwitchActionPromoter"/>
|
||||
<actionPromoter implementation="com.intellij.codeInsight.editorActions.JavaNextParameterActionPromoter"/>
|
||||
<java.error.fix errorCode="lambda.variable.must.be.final"
|
||||
<java.error.fix errorCode="variable.must.be.effectively.final.lambda"
|
||||
implementationClass="com.intellij.codeInsight.daemon.impl.quickfix.VariableAccessFromInnerClassJava10Fix"/>
|
||||
<java.error.fix errorCode="guarded.pattern.variable.must.be.final"
|
||||
<java.error.fix errorCode="variable.must.be.effectively.final.guard"
|
||||
implementationClass="com.intellij.codeInsight.daemon.impl.quickfix.VariableAccessFromInnerClassJava10Fix"/>
|
||||
<stripTrailingSpacesFilterFactory implementation="com.intellij.codeEditor.JavaStripTrailingSpacesFilterFactory"/>
|
||||
|
||||
|
||||
+1
-1
@@ -170,7 +170,7 @@ public final class BringVariableIntoScopeFix implements ModCommandAction {
|
||||
outOfScopeVariable.delete();
|
||||
}
|
||||
|
||||
if (HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(reference, addedVar, new HashMap<>(), file) != null) {
|
||||
if (!HighlightControlFlowUtil.isInitializedBeforeUsage(reference, addedVar, new HashMap<>(), false)) {
|
||||
initialize(addedVar);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -317,10 +317,12 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
|
||||
Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> finalVarProblems = new HashMap<>();
|
||||
for (PsiReferenceExpression expression : references) {
|
||||
if (ControlFlowUtil.isVariableAssignedInLoop(expression, variable)) return false;
|
||||
HighlightInfo.Builder highlightInfo = HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, variable, uninitializedVarProblems,
|
||||
variable.getContainingFile());
|
||||
if (highlightInfo != null) return false;
|
||||
highlightInfo = HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, finalVarProblems);
|
||||
if (!HighlightControlFlowUtil.isInitializedBeforeUsage(
|
||||
expression, variable, uninitializedVarProblems, false)) {
|
||||
return false;
|
||||
}
|
||||
HighlightInfo.Builder highlightInfo =
|
||||
HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, finalVarProblems);
|
||||
if (highlightInfo != null) return false;
|
||||
if (variable instanceof PsiParameter && PsiUtil.isAccessedForWriting(expression)) return false;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public final class ControlFlowUtil {
|
||||
* @param variable variable
|
||||
* @param context the context that references to the variable
|
||||
* @return the scope around context that enforces variable to be effectively final. Currently, it could be
|
||||
* an inner class, lambda expression, or switch guard. Returns null if there's no such scope,
|
||||
* an inner class, lambda expression, or {@link PsiSwitchLabelStatementBase} for switch guard. Returns null if there's no such scope,
|
||||
* or the variable declaration is within the same scope, so it should not be effectively final.
|
||||
* Note that if null is returned, it doesn't mean that the variable could be modified, as another reference from
|
||||
* another place might exist.
|
||||
|
||||
+12
-12
@@ -3,20 +3,20 @@ import java.util.function.*;
|
||||
class Test {
|
||||
void test1(Object o, int mode) {
|
||||
switch (o) {
|
||||
case Integer i when i == <error descr="Variable used in guarded pattern should be final or effectively final">mode</error> -> System.out.println();
|
||||
case Integer i when i == <error descr="Variable used in guard expression should be final or effectively final">mode</error> -> System.out.println();
|
||||
default -> {}
|
||||
}
|
||||
|
||||
switch (o) {
|
||||
case Integer i when (switch (o) {
|
||||
case Integer ii when ii != <error descr="Variable used in guarded pattern should be final or effectively final">mode</error> -> 2;
|
||||
case Integer ii when ii != <error descr="Variable used in guard expression should be final or effectively final">mode</error> -> 2;
|
||||
default -> 1;
|
||||
}) == <error descr="Variable used in guarded pattern should be final or effectively final">mode</error> -> System.out.println();
|
||||
}) == <error descr="Variable used in guard expression should be final or effectively final">mode</error> -> System.out.println();
|
||||
default -> {}
|
||||
}
|
||||
|
||||
switch (o) {
|
||||
case Integer i when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> System.out.println();
|
||||
case Integer i when (i = <error descr="Variable used in guard expression should be final or effectively final">mode</error>) > 0 -> System.out.println();
|
||||
default -> {}
|
||||
}
|
||||
mode = 0;
|
||||
@@ -24,7 +24,7 @@ class Test {
|
||||
|
||||
void test2(Object o, final int mode) {
|
||||
switch (o) {
|
||||
case Integer i when (switch (<error descr="Variable used in guarded pattern should be final or effectively final">o</error>) {
|
||||
case Integer i when (switch (<error descr="Variable used in guard expression should be final or effectively final">o</error>) {
|
||||
case Integer ii when ii != mode -> 2;
|
||||
default -> 1;
|
||||
}) == mode -> o = null;
|
||||
@@ -60,7 +60,7 @@ class Test {
|
||||
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) {
|
||||
case Integer i when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> System.out.println();
|
||||
case Integer i when (i = <error descr="Variable used in guard expression should be final or effectively final">mode</error>) > 0 -> System.out.println();
|
||||
default -> System.out.println();
|
||||
}
|
||||
default : break;
|
||||
@@ -69,7 +69,7 @@ class Test {
|
||||
str = 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) {
|
||||
case Integer i when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> "";
|
||||
case Integer i when (i = <error descr="Variable used in guard expression should be final or effectively final">mode</error>) > 0 -> "";
|
||||
default -> "";
|
||||
};
|
||||
default -> "";
|
||||
@@ -77,21 +77,21 @@ class Test {
|
||||
str = 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:
|
||||
yield switch (o) {
|
||||
case Integer i when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> "";
|
||||
case Integer i when (i = <error descr="Variable used in guard expression should be final or effectively final">mode</error>) > 0 -> "";
|
||||
default -> "";
|
||||
};
|
||||
default: yield "";
|
||||
};
|
||||
// lambdas
|
||||
str = switch (o) {
|
||||
case Integer i when (i = <error descr="Variable used in guarded pattern should be final or effectively final">in</error>) > 0:
|
||||
case Integer i when (i = <error descr="Variable used in guard expression should be final or effectively final">in</error>) > 0:
|
||||
yield ((Function<Integer, String>)(x) -> (<error descr="Variable used in lambda expression should be final or effectively final">in</error> = 5) > 0 ? "" : null).apply(in);
|
||||
default:
|
||||
yield "";
|
||||
};
|
||||
Consumer<Integer> c = (mode) -> {
|
||||
switch (o) {
|
||||
case Integer i when (i = <error descr="Variable used in guarded pattern should be final or effectively final">in</error>) > 0 -> System.out.println();
|
||||
case Integer i when (i = <error descr="Variable used in guard expression should be final or effectively final">in</error>) > 0 -> System.out.println();
|
||||
default -> System.out.println();
|
||||
}
|
||||
<error descr="Variable used in lambda expression should be final or effectively final">in</error> = 1;
|
||||
@@ -110,7 +110,7 @@ class Test {
|
||||
switch (o) {
|
||||
case Integer i -> {
|
||||
switch (o) {
|
||||
case Integer ii when ii > <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>:
|
||||
case Integer ii when ii > <error descr="Variable used in guard expression should be final or effectively final">mode</error>:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -174,7 +174,7 @@ class Test {
|
||||
public static void testWhenReassigned() {
|
||||
Object object = "1234";
|
||||
switch (object) {
|
||||
case String s when <error descr="Variable used in guarded pattern should be final or effectively final">s</error>.length()==2 -> {
|
||||
case String s when <error descr="Variable used in guard expression should be final or effectively final">s</error>.length()==2 -> {
|
||||
s = null;
|
||||
}
|
||||
default -> {
|
||||
|
||||
+3
-3
@@ -35,13 +35,13 @@ class Main {
|
||||
void nestedStatement(Object o, Object o2, int p) {
|
||||
int m = 0;
|
||||
switch (o) {
|
||||
case Integer n when <error descr="Variable used in guarded pattern should be final or effectively final">n</error> < 1:
|
||||
case Integer n when <error descr="Variable used in guard expression should be final or effectively final">n</error> < 1:
|
||||
n ++;
|
||||
case Integer n when n > 1:
|
||||
switch(o2) {
|
||||
case Integer <error descr="Variable 'm' is already defined in the scope">m</error> when <error descr="Variable used in guarded pattern should be final or effectively final">m</error> > 0:
|
||||
case Integer <error descr="Variable 'm' is already defined in the scope">m</error> when <error descr="Variable used in guard expression should be final or effectively final">m</error> > 0:
|
||||
m += n;
|
||||
case Integer <error descr="Variable 'p' is already defined in the scope">p</error> when <error descr="Variable used in guarded pattern should be final or effectively final">p</error> > 0:
|
||||
case Integer <error descr="Variable 'p' is already defined in the scope">p</error> when <error descr="Variable used in guard expression should be final or effectively final">p</error> > 0:
|
||||
p += n + m;
|
||||
break;
|
||||
case Integer p1:
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
groupKey="group.names.language.level.specific.issues.and.migration.aids8" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.intellij.refactoring.typeMigration.inspections.GuavaInspection"
|
||||
bundle="messages.TypeMigrationBundle" key="inspection.guava.name"/>
|
||||
<java.error.fix errorCode="lambda.variable.must.be.final" implementationClass="com.intellij.refactoring.typeMigration.intentions.ConvertFieldToAtomicIntention$ConvertNonFinalLocalToAtomicFix"/>
|
||||
<java.error.fix errorCode="variable.must.be.effectively.final.lambda"
|
||||
implementationClass="com.intellij.refactoring.typeMigration.intentions.ConvertFieldToAtomicIntention$ConvertNonFinalLocalToAtomicFix"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
+1
-2
@@ -22,8 +22,7 @@
|
||||
<descriptionDirectoryName>customDescriptionDirectory</descriptionDirectoryName>
|
||||
</intentionAction>
|
||||
|
||||
<java.error.fix errorCode="unhandled.exceptions"
|
||||
implementationClass="MyJavaErrorFix"/>
|
||||
<java.error.fix errorCode="exception.unhandled" implementationClass="MyJavaErrorFix"/>
|
||||
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -83,7 +83,7 @@
|
||||
<fileBasedIndex implementation="de.plushnikov.intellij.plugin.lombokconfig.LombokConfigIndex"/>
|
||||
|
||||
<custom.exception.handler implementation="de.plushnikov.intellij.plugin.handler.SneakyThrowsExceptionHandler"/>
|
||||
<java.error.fix errorCode="unhandled.exceptions" implementationClass="de.plushnikov.intellij.plugin.handler.AddSneakyThrowsAnnotationCommandAction"/>
|
||||
<java.error.fix errorCode="exception.unhandled" implementationClass="de.plushnikov.intellij.plugin.handler.AddSneakyThrowsAnnotationCommandAction"/>
|
||||
|
||||
<implicit.resource.closer
|
||||
implementation="de.plushnikov.intellij.plugin.extension.LombokCleanUpImplicitResourceCloser"/>
|
||||
|
||||
Reference in New Issue
Block a user