From 1cd294e40d9d1d071c06f2add62b1e74428ef363 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Wed, 5 Feb 2025 18:51:40 +0100 Subject: [PATCH] [java-highlighting] The rest of control-flow-related stuff (checkFinalVariableMightAlreadyHaveBeenAssignedTo) migrated More utility methods inside ControlFlowUtil Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: d4c294ce18da2032a0686f66794a7f377549edd2 --- .../JavaCompilationErrorBundle.properties | 5 + .../highlighting/ControlFlowChecker.java | 18 +- .../highlighting/JavaErrorVisitor.java | 6 +- .../highlighting/errors/JavaErrorKinds.java | 15 ++ .../analysis/HighlightControlFlowUtil.java | 218 +----------------- .../impl/analysis/HighlightFixUtil.java | 24 +- .../impl/analysis/HighlightVisitorImpl.java | 9 - .../impl/analysis/JavaErrorFixProvider.java | 7 + .../ReassignedVariableInspection.java | 9 +- .../codeInspection/dataFlow/DfaPsiUtil.java | 4 +- .../src/com/siyeh/ig/psiutils/FinalUtils.java | 7 +- .../VariableAccessFromInnerClassFix.java | 9 +- .../lookup/VariableLookupItem.java | 3 +- .../impl/rules/JavaUsageTypeProvider.java | 4 +- .../util/CommonJavaRefactoringUtil.java | 4 +- .../psi/controlFlow/ControlFlowUtil.java | 176 ++++++++++++++ .../FieldDoubleInitialization.java | 18 +- .../RecursiveConstructorInvocation.java | 2 +- .../OrderAlreadyInitializedErrors.java | 8 +- .../RecordConstructors.java | 4 +- 20 files changed, 268 insertions(+), 282 deletions(-) diff --git a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties index 3f6ad8b02bc1..eab5c5f58f18 100644 --- a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties +++ b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties @@ -379,6 +379,11 @@ variable.must.be.effectively.final=Variable ''{0}'' is accessed from within inne 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 variable.not.initialized=Variable ''{0}'' might not have been initialized +variable.already.assigned=Variable ''{0}'' might already have been assigned to +variable.already.assigned.constructor=Cannot assign final field ''{0}'' after chained constructor call +variable.already.assigned.field=Final field ''{0}'' is already initialized in another field initializer +variable.already.assigned.initializer=Final field ''{0}'' is already initialized in a class initializer +variable.assigned.in.loop=Variable ''{0}'' might be assigned in loop field.not.initialized=Field ''{0}'' might not have been initialized instanceof.type.parameter=Class or array expected diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ControlFlowChecker.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ControlFlowChecker.java index c601f3e9a728..f0fe6f266a94 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ControlFlowChecker.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ControlFlowChecker.java @@ -120,7 +120,6 @@ final class ControlFlowChecker { 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)); @@ -139,13 +138,28 @@ final class ControlFlowChecker { myVisitor.report(JavaErrorKinds.FIELD_NOT_INITIALIZED.create(field)); } - void checkVariableInitializedBeforeUsage(@NotNull PsiReferenceExpression expression, @NotNull PsiVariable variable) { + void checkVariableInitializedBeforeUsage(@NotNull PsiVariable variable, @NotNull PsiReferenceExpression expression) { if (ControlFlowUtil.isInitializedBeforeUsage(expression, variable, myUninitializedVarProblems, false)) { return; } myVisitor.report(JavaErrorKinds.VARIABLE_NOT_INITIALIZED.create(expression, variable)); } + void checkFinalVariableMightAlreadyHaveBeenAssignedTo(@NotNull PsiVariable variable, @NotNull PsiReferenceExpression expression) { + ControlFlowUtil.DoubleInitializationProblem + problem = ControlFlowUtil.findFinalVariableAlreadyInitializedProblem(variable, expression, myFinalVarProblems); + var kind = switch (problem) { + case NORMAL -> JavaErrorKinds.VARIABLE_ALREADY_ASSIGNED; + case IN_LOOP -> JavaErrorKinds.VARIABLE_ASSIGNED_IN_LOOP; + case IN_CONSTRUCTOR -> JavaErrorKinds.VARIABLE_ALREADY_ASSIGNED_CONSTRUCTOR; + case IN_FIELD_INITIALIZER -> JavaErrorKinds.VARIABLE_ALREADY_ASSIGNED_FIELD; + case IN_INITIALIZER -> JavaErrorKinds.VARIABLE_ALREADY_ASSIGNED_INITIALIZER; + case NO_PROBLEM -> null; + }; + if (kind == null) return; + myVisitor.report(kind.create(expression, variable)); + } + /** * @return field that has initializer with this element as subexpression or null if not found */ diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java index c95afda31bfa..3df395d74390 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java @@ -706,7 +706,11 @@ final class JavaErrorVisitor extends JavaElementVisitor { if (!hasErrorResults() && resolved instanceof PsiLocalVariable localVariable) { myExpressionChecker.checkVarTypeSelfReferencing(localVariable, expression); } - if (!hasErrorResults()) myControlFlowChecker.checkVariableInitializedBeforeUsage(expression, variable); + boolean isFinal = variable.hasModifierProperty(PsiModifier.FINAL); + if (isFinal && !variable.hasInitializer() && !(variable instanceof PsiPatternVariable)) { + if (!hasErrorResults()) myControlFlowChecker.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression); + } + if (!hasErrorResults()) myControlFlowChecker.checkVariableInitializedBeforeUsage(variable, expression); } if (parent instanceof PsiMethodCallExpression methodCallExpression && methodCallExpression.getMethodExpression() == expression && diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java index 07c8e3dbb2bc..3d6c44fdbc26 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java @@ -1243,6 +1243,21 @@ public final class JavaErrorKinds { public static final Parameterized VARIABLE_NOT_INITIALIZED = parameterized(PsiReferenceExpression.class, PsiVariable.class, "variable.not.initialized") .withRawDescription((ref, var) -> message("variable.not.initialized", var.getName())); + public static final Parameterized VARIABLE_ALREADY_ASSIGNED = + parameterized(PsiReferenceExpression.class, PsiVariable.class, "variable.already.assigned") + .withRawDescription((ref, var) -> message("variable.already.assigned", var.getName())); + public static final Parameterized VARIABLE_ALREADY_ASSIGNED_CONSTRUCTOR = + parameterized(PsiReferenceExpression.class, PsiVariable.class, "variable.already.assigned.constructor") + .withRawDescription((ref, var) -> message("variable.already.assigned.constructor", var.getName())); + public static final Parameterized VARIABLE_ALREADY_ASSIGNED_FIELD = + parameterized(PsiReferenceExpression.class, PsiVariable.class, "variable.already.assigned.field") + .withRawDescription((ref, var) -> message("variable.already.assigned.field", var.getName())); + public static final Parameterized VARIABLE_ALREADY_ASSIGNED_INITIALIZER = + parameterized(PsiReferenceExpression.class, PsiVariable.class, "variable.already.assigned.initializer") + .withRawDescription((ref, var) -> message("variable.already.assigned.initializer", var.getName())); + public static final Parameterized VARIABLE_ASSIGNED_IN_LOOP = + parameterized(PsiReferenceExpression.class, PsiVariable.class, "variable.assigned.in.loop") + .withRawDescription((ref, var) -> message("variable.assigned.in.loop", var.getName())); public static final Parameterized VARIABLE_MUST_BE_FINAL = parameterized(PsiJavaCodeReferenceElement.class, PsiVariable.class, "variable.must.be.final") .withRawDescription((ref, var) -> message("variable.must.be.final", var.getName())); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 31137d8798c9..cb824c13b0fe 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -1,30 +1,20 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.daemon.impl.analysis; -import com.intellij.codeInsight.daemon.JavaErrorBundle; -import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.daemon.impl.HighlightInfoType; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.QuickFixFactory; -import com.intellij.psi.*; -import com.intellij.psi.controlFlow.*; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.JavaPsiConstructorUtil; -import com.intellij.util.Processor; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiVariable; +import com.intellij.psi.controlFlow.AnalysisCanceledException; +import com.intellij.psi.controlFlow.ControlFlow; +import com.intellij.psi.controlFlow.ControlFlowFactory; +import com.intellij.psi.controlFlow.ControlFlowUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; +/** + * @deprecated all the methods are deprecated + */ +@Deprecated public final class HighlightControlFlowUtil { - private static QuickFixFactory getQuickFixFactory() { - return QuickFixFactory.getInstance(); - } - private HighlightControlFlowUtil() { } /** @@ -42,192 +32,4 @@ public final class HighlightControlFlowUtil { public static boolean variableDefinitelyAssignedIn(@NotNull PsiVariable variable, @NotNull PsiElement context) { return ControlFlowUtil.variableDefinitelyAssignedIn(variable, context); } - - private static @NotNull ControlFlow getControlFlow(@NotNull PsiElement context) throws AnalysisCanceledException { - LocalsOrMyInstanceFieldsControlFlowPolicy policy = LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(); - return ControlFlowFactory.getControlFlow(context, policy, ControlFlowOptions.create(true, true, true)); - } - - public static boolean isAssigned(@NotNull PsiParameter parameter) { - ParamWriteProcessor processor = new ParamWriteProcessor(); - ReferencesSearch.search(parameter, new LocalSearchScope(parameter.getDeclarationScope()), true).forEach(processor); - return processor.isWriteRefFound(); - } - - private static class ParamWriteProcessor implements Processor { - private volatile boolean myIsWriteRefFound; - @Override - public boolean process(@NotNull PsiReference reference) { - PsiElement element = reference.getElement(); - if (element instanceof PsiReferenceExpression ref && PsiUtil.isAccessedForWriting(ref)) { - myIsWriteRefFound = true; - return false; - } - return true; - } - - private boolean isWriteRefFound() { - return myIsWriteRefFound; - } - } - - private static boolean variableDefinitelyNotAssignedIn(@NotNull PsiVariable variable, @NotNull PsiElement context) { - try { - return ControlFlowUtil.isVariableDefinitelyNotAssigned(variable, getControlFlow(context)); - } - catch (AnalysisCanceledException e) { - return true; - } - } - - /** - * @param variable variable to check - * @param finalVarProblems cache map to reuse information - * @return true if variable is reassigned - */ - public static boolean isReassigned(@NotNull PsiVariable variable, - @NotNull Map> finalVarProblems) { - if (variable instanceof PsiLocalVariable) { - PsiElement parent = variable.getParent(); - if (parent == null) return false; - PsiElement declarationScope = parent.getParent(); - if (declarationScope == null) return false; - Collection codeBlockProblems = getFinalVariableProblemsInBlock(finalVarProblems, declarationScope); - return codeBlockProblems.contains(new ControlFlowUtil.VariableInfo(variable, null)); - } - if (variable instanceof PsiParameter parameter) { - return isAssigned(parameter); - } - return false; - } - - - public static HighlightInfo.Builder checkFinalVariableMightAlreadyHaveBeenAssignedTo(@NotNull PsiVariable variable, - @NotNull PsiReferenceExpression expression, - @NotNull Map> finalVarProblems) { - if (!PsiUtil.isAccessedForWriting(expression)) return null; - - PsiElement scope = variable instanceof PsiField - ? variable.getParent() - : variable.getParent() == null ? null : variable.getParent().getParent(); - PsiElement codeBlock = PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope); - if (codeBlock == null) return null; - Collection codeBlockProblems = getFinalVariableProblemsInBlock(finalVarProblems, codeBlock); - - boolean inLoop = false; - boolean canDefer = false; - ControlFlowUtil.VariableInfo variableInfo = ContainerUtil.find(codeBlockProblems, vi -> vi.expression == expression); - if (variableInfo != null) { - inLoop = variableInfo instanceof InitializedInLoopProblemInfo; - canDefer = !inLoop; - } - else if (!(variable instanceof PsiField field && isFieldInitializedInAnotherMember(field, expression, codeBlock))) { - return null; - } - - String description = - JavaErrorBundle.message(inLoop ? "variable.assigned.in.loop" : "variable.already.assigned", variable.getName()); - HighlightInfo.Builder highlightInfo = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description); - if (canDefer) { - IntentionAction action = getQuickFixFactory().createDeferFinalAssignmentFix(variable, expression); - highlightInfo.registerFix(action, null, null, null, null); - } - HighlightFixUtil.registerMakeNotFinalAction(variable, highlightInfo); - return highlightInfo; - } - - private static boolean isFieldInitializedInAnotherMember(@NotNull PsiField field, - @NotNull PsiReferenceExpression expression, - @NotNull PsiElement codeBlock) { - PsiClass aClass = field.getContainingClass(); - if (aClass == null) return false; - boolean isFieldStatic = field.hasModifierProperty(PsiModifier.STATIC); - PsiMember enclosingConstructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expression); - - if (!isFieldStatic) { - // constructor that delegates to another constructor cannot assign final fields - if (enclosingConstructorOrInitializer instanceof PsiMethod method) { - PsiMethodCallExpression chainedCall = JavaPsiConstructorUtil.findThisOrSuperCallInConstructor(method); - if (JavaPsiConstructorUtil.isChainedConstructorCall(chainedCall)) { - return true; - } - } - } - - // field can get assigned in other field initializers or in class initializers - List members = new ArrayList<>(Arrays.asList(aClass.getFields())); - if (enclosingConstructorOrInitializer != null - && aClass.getManager().areElementsEquivalent(enclosingConstructorOrInitializer.getContainingClass(), aClass)) { - members.addAll(Arrays.asList(aClass.getInitializers())); - members.sort(PsiUtil.BY_POSITION); - } - - for (PsiMember member : members) { - if (member == field) continue; - PsiElement context = member instanceof PsiField f ? f.getInitializer() : ((PsiClassInitializer)member).getBody(); - - if (context != null - && member.hasModifierProperty(PsiModifier.STATIC) == isFieldStatic - && !variableDefinitelyNotAssignedIn(field, context)) { - return context != codeBlock; - } - } - return false; - } - - private static @NotNull Collection getFinalVariableProblemsInBlock(@NotNull Map> finalVarProblems, - @NotNull PsiElement codeBlock) { - Collection codeBlockProblems = finalVarProblems.get(codeBlock); - if (codeBlockProblems == null) { - try { - ControlFlow controlFlow = getControlFlow(codeBlock); - codeBlockProblems = ControlFlowUtil.getInitializedTwice(controlFlow); - codeBlockProblems = addReassignedInLoopProblems(codeBlockProblems, controlFlow); - } - catch (AnalysisCanceledException e) { - codeBlockProblems = Collections.emptyList(); - } - finalVarProblems.put(codeBlock, codeBlockProblems); - } - return codeBlockProblems; - } - - private static Collection addReassignedInLoopProblems( - @NotNull Collection codeBlockProblems, - @NotNull ControlFlow controlFlow) { - List instructions = controlFlow.getInstructions(); - for (int index = 0; index < instructions.size(); index++) { - Instruction instruction = instructions.get(index); - if (instruction instanceof WriteVariableInstruction wvi) { - PsiVariable variable = wvi.variable; - if (variable instanceof PsiLocalVariable || variable instanceof PsiField) { - PsiElement anchor = controlFlow.getElement(index); - if (anchor instanceof PsiAssignmentExpression assignment) { - PsiExpression ref = PsiUtil.skipParenthesizedExprDown(assignment.getLExpression()); - if (ref instanceof PsiReferenceExpression) { - ControlFlowUtil.VariableInfo varInfo = new InitializedInLoopProblemInfo(variable, ref); - if (!codeBlockProblems.contains(varInfo) && ControlFlowUtil.isInstructionReachable(controlFlow, index, index)) { - if (!(codeBlockProblems instanceof HashSet)) { - codeBlockProblems = new HashSet<>(codeBlockProblems); - } - codeBlockProblems.add(varInfo); - } - } - } - } - } - } - return codeBlockProblems; - } - - /** - * A kind of final variable problem returned from {@link #getFinalVariableProblemsInBlock(Map, PsiElement)} - * which designates a final variable which is initialized in a loop. - */ - private static class InitializedInLoopProblemInfo extends ControlFlowUtil.VariableInfo { - InitializedInLoopProblemInfo(@NotNull PsiVariable variable, @Nullable PsiElement expression) { - super(variable, expression); - } - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java index dd512064ac0e..415a01565151 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightFixUtil.java @@ -2,7 +2,6 @@ package com.intellij.codeInsight.daemon.impl.analysis; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.quickfix.*; import com.intellij.codeInsight.intention.CommonIntentionAction; import com.intellij.codeInsight.intention.IntentionAction; @@ -41,7 +40,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Consumer; -import static java.util.Objects.*; +import static java.util.Objects.requireNonNullElse; public final class HighlightFixUtil { private static final Logger LOG = Logger.getInstance(HighlightFixUtil.class); @@ -184,12 +183,6 @@ public final class HighlightFixUtil { return qname == null || !Character.isLowerCase(qname.charAt(0)); } - static void registerChangeVariableTypeFixes(@NotNull PsiVariable parameter, - @Nullable PsiType itemType, - @Nullable HighlightInfo.Builder highlightInfo) { - registerChangeVariableTypeFixes(parameter, itemType, HighlightUtil.asConsumer(highlightInfo)); - } - static void registerChangeVariableTypeFixes(@NotNull PsiVariable parameter, @Nullable PsiType itemType, @NotNull Consumer info) { @@ -351,21 +344,6 @@ public final class HighlightFixUtil { return null; } - static void registerMakeNotFinalAction(@NotNull PsiVariable var, @Nullable HighlightInfo.Builder highlightInfo) { - if (var instanceof PsiField) { - QuickFixAction.registerQuickFixActions( - highlightInfo, null, - JvmElementActionFactories.createModifierActions((PsiField)var, MemberRequestsKt.modifierRequest(JvmModifier.FINAL, false)) - ); - } - else { - IntentionAction action = QuickFixFactory.getInstance().createModifierListFix(var, PsiModifier.FINAL, false, false); - if (highlightInfo != null) { - highlightInfo.registerFix(action, null, null, null, null); - } - } - } - public static void registerFixesForExpressionStatement(@NotNull PsiElement statement, @NotNull Consumer info) { if (!(statement instanceof PsiExpressionStatement)) return; PsiCodeBlock block = ObjectUtils.tryCast(statement.getParent(), PsiCodeBlock.class); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 959660163932..727da72d4801 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -475,15 +475,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY; PsiElement resolved = result.getElement(); - if (resolved instanceof PsiVariable variable && resolved.getContainingFile() == expression.getContainingFile()) { - boolean isFinal = variable.hasModifierProperty(PsiModifier.FINAL); - if (isFinal && !variable.hasInitializer() && !(variable instanceof PsiPatternVariable)) { - if (!hasErrorResults()) { - add(HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, myFinalVarProblems)); - } - } - } - if (!hasErrorResults()) add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved)); PsiExpression qualifierExpression = expression.getQualifierExpression(); if (!hasErrorResults() && myJavaModule == null && qualifierExpression != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java index 540cd94451d4..13b452ae0a99 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java @@ -388,6 +388,13 @@ final class JavaErrorFixProvider { 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())); + fix(VARIABLE_ALREADY_ASSIGNED, error -> myFactory.createDeferFinalAssignmentFix(error.context(), error.psi())); + fix(VARIABLE_ALREADY_ASSIGNED, error -> removeModifierFix(error.context(), PsiModifier.FINAL)); + fix(VARIABLE_ALREADY_ASSIGNED_FIELD, error -> removeModifierFix(error.context(), PsiModifier.FINAL)); + fix(VARIABLE_ALREADY_ASSIGNED_CONSTRUCTOR, error -> removeModifierFix(error.context(), PsiModifier.FINAL)); + fix(VARIABLE_ALREADY_ASSIGNED_INITIALIZER, error -> removeModifierFix(error.context(), PsiModifier.FINAL)); + fix(VARIABLE_ASSIGNED_IN_LOOP, error -> removeModifierFix(error.context(), PsiModifier.FINAL)); + fixes(FIELD_NOT_INITIALIZED, (error, sink) -> { PsiField field = error.psi(); sink.accept(myFactory.createCreateConstructorParameterFromFieldFix(field)); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/ReassignedVariableInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/ReassignedVariableInspection.java index 36f4f4b2d288..c6d536cc7a17 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/ReassignedVariableInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/ReassignedVariableInspection.java @@ -1,10 +1,10 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInspection; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.java.JavaBundle; import com.intellij.psi.*; import com.intellij.psi.controlFlow.ControlFlowUtil; +import com.siyeh.ig.psiutils.VariableAccessUtils; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -42,7 +42,7 @@ public final class ReassignedVariableInspection extends AbstractBaseJavaLocalIns PsiIdentifier nameIdentifier = variable.getNameIdentifier(); if (nameIdentifier != null && !variable.hasModifierProperty(PsiModifier.FINAL) && - HighlightControlFlowUtil.isReassigned(variable, myLocalVariableProblems)) { + ControlFlowUtil.isReassigned(variable, myLocalVariableProblems)) { myHolder.registerProblem(nameIdentifier, getReassignedMessage(variable)); return true; } @@ -60,13 +60,12 @@ public final class ReassignedVariableInspection extends AbstractBaseJavaLocalIns !((PsiVariable)resolved).hasModifierProperty(PsiModifier.FINAL) && !SuppressionUtil.inspectionResultSuppressed(resolved, ReassignedVariableInspection.this)) { if (resolved instanceof PsiLocalVariable) { - if (HighlightControlFlowUtil.isReassigned((PsiVariable)resolved, myLocalVariableProblems)) { + if (ControlFlowUtil.isReassigned((PsiVariable)resolved, myLocalVariableProblems)) { myHolder.registerProblem(referenceNameElement, getReassignedMessage((PsiVariable)resolved)); } } else { - Boolean isReassigned = myParameterIsReassigned.computeIfAbsent((PsiParameter)resolved, - HighlightControlFlowUtil::isAssigned); + Boolean isReassigned = myParameterIsReassigned.computeIfAbsent((PsiParameter)resolved, VariableAccessUtils::variableIsAssigned); if (isReassigned) { myHolder.registerProblem(referenceNameElement, getReassignedMessage((PsiVariable)resolved)); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java index 45899e8a91e9..d97c899e4fb2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java @@ -5,7 +5,6 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.Nullability; import com.intellij.codeInsight.NullabilityAnnotationInfo; import com.intellij.codeInsight.NullableNotNullManager; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil; import com.intellij.codeInspection.dataFlow.interpreter.RunnerResult; import com.intellij.codeInspection.dataFlow.interpreter.StandardDataFlowInterpreter; @@ -37,6 +36,7 @@ import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; @@ -231,7 +231,7 @@ public final class DfaPsiUtil { refExpr.resolve() instanceof PsiParameter parameter && parameter.getParent() instanceof PsiForeachStatement targetLoop && PsiTreeUtil.isAncestor(targetLoop, loop, true) && - !HighlightControlFlowUtil.isReassigned(parameter, new HashMap<>())) { + !ControlFlowUtil.isReassigned(parameter, new HashMap<>())) { iteratedType = inferLoopParameterTypeWithNullability(targetLoop); } return JavaGenericsUtil.getCollectionItemType(iteratedType, iteratedValue.getResolveScope()); diff --git a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/FinalUtils.java b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/FinalUtils.java index 2d34d626206d..2d8aa09496fd 100644 --- a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/FinalUtils.java +++ b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/FinalUtils.java @@ -1,8 +1,6 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ig.psiutils; -import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.psi.*; import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.controlFlow.LocalsOrMyInstanceFieldsControlFlowPolicy; @@ -69,8 +67,7 @@ public final class FinalUtils { PsiElement innerScope = ControlFlowUtil.getScopeEnforcingEffectiveFinality(variable, ref); if (innerScope != null && innerScope != ((PsiField)variable).getContainingClass()) return false; } - HighlightInfo.Builder random = - HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, ref, finalVarProblems); - return random == null; + return ControlFlowUtil.findFinalVariableAlreadyInitializedProblem(variable, ref, finalVarProblems) == + ControlFlowUtil.DoubleInitializationProblem.NO_PROBLEM; } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java index 77b388c2bbb5..c5f190374daf 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java @@ -2,8 +2,6 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil; import com.intellij.codeInsight.intention.FileModifier; import com.intellij.codeInsight.intention.IntentionAction; @@ -321,9 +319,10 @@ public class VariableAccessFromInnerClassFix implements IntentionAction { expression, variable, uninitializedVarProblems, false)) { return false; } - HighlightInfo.Builder highlightInfo = - HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, finalVarProblems); - if (highlightInfo != null) return false; + if (ControlFlowUtil.findFinalVariableAlreadyInitializedProblem(variable, expression, finalVarProblems) != + ControlFlowUtil.DoubleInitializationProblem.NO_PROBLEM) { + return false; + } if (variable instanceof PsiParameter && PsiUtil.isAccessedForWriting(expression)) return false; } return true; diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java index a8887a4f5578..b28c2be3041b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java @@ -5,7 +5,6 @@ import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.TailTypes; import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.daemon.impl.JavaColorProvider; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInsight.daemon.impl.quickfix.BringVariableIntoScopeFix; import com.intellij.codeInsight.lookup.impl.JavaElementLookupRenderer; import com.intellij.codeInspection.dataFlow.jvm.descriptors.PlainDescriptor; @@ -306,7 +305,7 @@ public class VariableLookupItem extends LookupItem implements Typed } if (ControlFlowUtil.getScopeEnforcingEffectiveFinality(variable, place) != null && - !HighlightControlFlowUtil.isReassigned(variable, new HashMap<>())) { + !ControlFlowUtil.isReassigned(variable, new HashMap<>())) { PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, true); } } diff --git a/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java b/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java index ece719faada6..da96dedcd310 100644 --- a/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java +++ b/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java @@ -1,12 +1,12 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.usages.impl.rules; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.usages.PsiElementUsageTarget; import com.intellij.usages.UsageTarget; +import com.siyeh.ig.psiutils.VariableAccessUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -78,7 +78,7 @@ public final class JavaUsageTypeProvider implements UsageTypeProviderEx { } for (PsiParameter parameter : parameters) { - if (HighlightControlFlowUtil.isAssigned(parameter)) return false; + if (VariableAccessUtils.variableIsAssigned(parameter)) return false; } return true; diff --git a/java/java-impl/src/com/intellij/util/CommonJavaRefactoringUtil.java b/java/java-impl/src/com/intellij/util/CommonJavaRefactoringUtil.java index 469146bcb202..9c79be5df26b 100644 --- a/java/java-impl/src/com/intellij/util/CommonJavaRefactoringUtil.java +++ b/java/java-impl/src/com/intellij/util/CommonJavaRefactoringUtil.java @@ -5,7 +5,6 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.completion.JavaCompletionUtil; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.lang.LanguageRefactoringSupport; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.diagnostic.Logger; @@ -22,6 +21,7 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.codeStyle.*; +import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.psi.impl.source.codeStyle.javadoc.CommentFormatter; import com.intellij.psi.javadoc.PsiDocComment; @@ -457,7 +457,7 @@ public final class CommonJavaRefactoringUtil { public static boolean canBeDeclaredFinal(@NotNull PsiVariable variable) { LOG.assertTrue(variable instanceof PsiLocalVariable || variable instanceof PsiParameter); - final boolean isReassigned = HighlightControlFlowUtil + final boolean isReassigned = ControlFlowUtil .isReassigned(variable, new HashMap<>()); return !isReassigned; } diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java index 83d86b370f7a..3311232bb95c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java @@ -435,6 +435,172 @@ public final class ControlFlowUtil { return false; } + private static boolean variableDefinitelyNotAssignedIn(@NotNull PsiVariable variable, @NotNull PsiElement context) { + ControlFlow flow = getControlFlow(context); + return flow == null || isVariableDefinitelyNotAssigned(variable, flow); + } + + /** + * Kind of double initialization problem + * + * @see #findFinalVariableAlreadyInitializedProblem(PsiVariable, PsiReferenceExpression, Map) + */ + public enum DoubleInitializationProblem { + NO_PROBLEM, + /** + * Final variable is reassigned normally + */ + NORMAL, + /** + * Final variable is reassigned in loop + */ + IN_LOOP, + /** + * Double initialization of a final field due to chained constructor call + */ + IN_CONSTRUCTOR, + /** + * Double initialization of a final field in other initializer + */ + IN_INITIALIZER, + /** + * Double initialization of a final field in other field initializer + */ + IN_FIELD_INITIALIZER + } + + /** + * @param variable final variable to check + * @param expression variable reference (write location) + * @param finalVarProblems a map to cache the results + * @return DoubleInitializationProblem object that depicts the problem kind + */ + public static @NotNull DoubleInitializationProblem findFinalVariableAlreadyInitializedProblem(@NotNull PsiVariable variable, + @NotNull PsiReferenceExpression expression, + @NotNull Map> finalVarProblems) { + if (!PsiUtil.isAccessedForWriting(expression)) return DoubleInitializationProblem.NO_PROBLEM; + + PsiElement scope = variable instanceof PsiField + ? variable.getParent() + : variable.getParent() == null ? null : variable.getParent().getParent(); + PsiElement codeBlock = PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope); + if (codeBlock == null) return DoubleInitializationProblem.NO_PROBLEM; + Collection codeBlockProblems = getFinalVariableProblemsInBlock(finalVarProblems, codeBlock); + + VariableInfo variableInfo = ContainerUtil.find(codeBlockProblems, vi -> vi.expression == expression); + if (variableInfo == null) { + if (variable instanceof PsiField) { + DoubleInitializationProblem problem = isFieldInitializedInAnotherMember((PsiField)variable, expression, codeBlock); + if (problem != null) { + return problem; + } + } + return DoubleInitializationProblem.NO_PROBLEM; + } + return variableInfo instanceof InitializedInLoopProblemInfo ? DoubleInitializationProblem.IN_LOOP : DoubleInitializationProblem.NORMAL; + } + + private static DoubleInitializationProblem isFieldInitializedInAnotherMember(@NotNull PsiField field, + @NotNull PsiReferenceExpression expression, + @NotNull PsiElement codeBlock) { + PsiClass aClass = field.getContainingClass(); + if (aClass == null) return null; + boolean isFieldStatic = field.hasModifierProperty(PsiModifier.STATIC); + PsiMember enclosingConstructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expression); + + if (!isFieldStatic) { + // constructor that delegates to another constructor cannot assign final fields + if (enclosingConstructorOrInitializer instanceof PsiMethod) { + PsiMethodCallExpression chainedCall = JavaPsiConstructorUtil.findThisOrSuperCallInConstructor( + (PsiMethod)enclosingConstructorOrInitializer); + if (JavaPsiConstructorUtil.isChainedConstructorCall(chainedCall)) { + return DoubleInitializationProblem.IN_CONSTRUCTOR; + } + } + } + + // field can get assigned in other field initializers or in class initializers + List members = new ArrayList<>(Arrays.asList(aClass.getFields())); + if (enclosingConstructorOrInitializer != null + && aClass.getManager().areElementsEquivalent(enclosingConstructorOrInitializer.getContainingClass(), aClass)) { + members.addAll(Arrays.asList(aClass.getInitializers())); + members.sort(PsiUtil.BY_POSITION); + } + + for (PsiMember member : members) { + if (member == field) continue; + PsiElement context = member instanceof PsiField ? ((PsiField)member).getInitializer() : ((PsiClassInitializer)member).getBody(); + + if (context != null + && member.hasModifierProperty(PsiModifier.STATIC) == isFieldStatic + && !variableDefinitelyNotAssignedIn(field, context)) { + return context == codeBlock ? null : + member instanceof PsiField ? DoubleInitializationProblem.IN_FIELD_INITIALIZER : + DoubleInitializationProblem.IN_INITIALIZER; + } + } + return null; + } + + private static @NotNull Collection getFinalVariableProblemsInBlock( + @NotNull Map> finalVarProblems, @NotNull PsiElement codeBlock) { + Collection codeBlockProblems = + finalVarProblems.computeIfAbsent(codeBlock, cb -> { + ControlFlow controlFlow = getControlFlow(codeBlock); + return controlFlow == null ? Collections.emptyList() : addReassignedInLoopProblems(getInitializedTwice(controlFlow), controlFlow); + }); + return codeBlockProblems; + } + + private static Collection addReassignedInLoopProblems( + @NotNull Collection codeBlockProblems, + @NotNull ControlFlow controlFlow) { + List instructions = controlFlow.getInstructions(); + for (int index = 0; index < instructions.size(); index++) { + Instruction instruction = instructions.get(index); + if (instruction instanceof WriteVariableInstruction) { + PsiVariable variable = ((WriteVariableInstruction)instruction).variable; + if (variable instanceof PsiLocalVariable || variable instanceof PsiField) { + PsiElement anchor = controlFlow.getElement(index); + if (anchor instanceof PsiAssignmentExpression) { + PsiExpression ref = PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)anchor).getLExpression()); + if (ref instanceof PsiReferenceExpression) { + VariableInfo varInfo = new InitializedInLoopProblemInfo(variable, ref); + if (!codeBlockProblems.contains(varInfo) && isInstructionReachable(controlFlow, index, index)) { + if (!(codeBlockProblems instanceof HashSet)) { + codeBlockProblems = new HashSet<>(codeBlockProblems); + } + codeBlockProblems.add(varInfo); + } + } + } + } + } + } + return codeBlockProblems; + } + + /** + * @param variable variable to check (local variable or parameter) + * @param finalVarProblems cache map to reuse information + * @return true if the variable is reassigned + */ + public static boolean isReassigned(@NotNull PsiVariable variable, @NotNull Map> finalVarProblems) { + if (variable instanceof PsiLocalVariable) { + PsiElement parent = variable.getParent(); + if (parent == null) return false; + PsiElement declarationScope = parent.getParent(); + if (declarationScope == null) return false; + Collection codeBlockProblems = getFinalVariableProblemsInBlock(finalVarProblems, declarationScope); + return codeBlockProblems.contains(new VariableInfo(variable, null)); + } + if (variable instanceof PsiParameter) { + PsiParameter parameter = (PsiParameter)variable; + return variableIsAssigned(parameter, parameter.getDeclarationScope()); + } + return false; + } + private static class SSAInstructionState { private final int myWriteCount; private final int myInstructionIdx; @@ -2303,6 +2469,16 @@ public final class ControlFlowUtil { } } + /** + * A kind of final variable problem returned from {@link #getFinalVariableProblemsInBlock(Map, PsiElement)} + * which designates a final variable which is initialized in a loop. + */ + private static class InitializedInLoopProblemInfo extends VariableInfo { + InitializedInLoopProblemInfo(@NotNull PsiVariable variable, @Nullable PsiElement expression) { + super(variable, expression); + } + } + private static void merge(int offset, CopyOnWriteList source, CopyOnWriteList @NotNull [] target) { if (source != null) { CopyOnWriteList existing = target[offset]; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/FieldDoubleInitialization.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/FieldDoubleInitialization.java index 2fecc6319565..f1ec0cfcbab7 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/FieldDoubleInitialization.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/FieldDoubleInitialization.java @@ -5,7 +5,7 @@ class Foo { final int k; final int ff = 5; Foo(int i) { - k =1; + k =1; } { k=0; @@ -21,7 +21,7 @@ class c2 { int i = k; } static { - k =1; + k =1; } } @@ -34,7 +34,7 @@ class c3 { int i = k; } { - k =1; + k =1; } } @@ -45,11 +45,11 @@ class c4 { } c4(int i) { if (false) - k =1; + k =1; } c4() { this(0); - k =1; + k =1; } } // redirected ctrs @@ -60,7 +60,7 @@ class c5 { } c5() { this(0); - k =1; + k =1; } @@ -68,11 +68,11 @@ class c5 { } c5(int i, int j) { this('c'); - k = 5; + k = 5; } c5(String s) { this(0,0); - k =1; + k =1; } } @@ -113,6 +113,6 @@ class c7 { } { - y = ""+i; + y = ""+i; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/RecursiveConstructorInvocation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/RecursiveConstructorInvocation.java index 3c4460cb7e4f..21879a6785a0 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/RecursiveConstructorInvocation.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/RecursiveConstructorInvocation.java @@ -40,6 +40,6 @@ class X { X() { this(); - value = 1; + value = 1; } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/OrderAlreadyInitializedErrors.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/OrderAlreadyInitializedErrors.java index d006a8345029..4a4b59af69c9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/OrderAlreadyInitializedErrors.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/OrderAlreadyInitializedErrors.java @@ -3,10 +3,10 @@ class A { c = "c"; } static String b = a = ""; - static String d = c = ""; + static String d = c = ""; static { - a = ""; + a = ""; } static final String a; static final String c; @@ -16,10 +16,10 @@ class B { c = "c"; } String b = a = ""; - String d = c = ""; + String d = c = ""; { - a = ""; + a = ""; } final String a; final String c; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordConstructors.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordConstructors.java index bd0e83832a4e..089ea3b65e8e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordConstructors.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingRecords/RecordConstructors.java @@ -35,7 +35,7 @@ record VarArgMismatch2(int[] x) { record Delegate(int x) { public Delegate(int x) { this(); - this.x = 0; + this.x = 0; } public Delegate() { @@ -67,7 +67,7 @@ record ImplicitCanonicalConstructor(String s) { record AssignmentInNonCanonical(int x, int y, long depth) { public AssignmentInNonCanonical(int x, int y) { this(x, y, 10); - this.x = x; + this.x = x; } void method() {