mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
Java: don't make final field red when constructor has incomplete code (IDEA-361300)
GitOrigin-RevId: b148be0a04eed2a8f5215f1650212733555bd403
This commit is contained in:
committed by
intellij-monorepo-bot
parent
534411cf4b
commit
fc99608c7a
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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;
|
||||
@@ -175,9 +175,9 @@ public final class HighlightControlFlowUtil {
|
||||
List<PsiMethod> redirectedConstructors = JavaHighlightUtil.getChainedConstructors(constructor);
|
||||
for (PsiMethod redirectedConstructor : redirectedConstructors) {
|
||||
PsiCodeBlock body = redirectedConstructor.getBody();
|
||||
if (body != null && variableDefinitelyAssignedIn(field, body)) continue nextConstructor;
|
||||
if (body != null && variableDefinitelyAssignedIn(field, body, true)) continue nextConstructor;
|
||||
}
|
||||
if (!ctrBody.isValid() || variableDefinitelyAssignedIn(field, ctrBody)) {
|
||||
if (!ctrBody.isValid() || variableDefinitelyAssignedIn(field, ctrBody, true)) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
@@ -190,7 +190,7 @@ public final class HighlightControlFlowUtil {
|
||||
boolean isFieldStatic,
|
||||
PsiClassInitializer @NotNull [] initializers) {
|
||||
return ContainerUtil.find(initializers, initializer -> initializer.hasModifierProperty(PsiModifier.STATIC) == isFieldStatic
|
||||
&& variableDefinitelyAssignedIn(field, initializer.getBody())) != null;
|
||||
&& variableDefinitelyAssignedIn(field, initializer.getBody(), true)) != null;
|
||||
}
|
||||
|
||||
private static boolean isFieldInitializedInOtherFieldInitializer(@NotNull PsiClass aClass,
|
||||
@@ -201,7 +201,7 @@ public final class HighlightControlFlowUtil {
|
||||
for (PsiField psiField : fields) {
|
||||
if (psiField != field
|
||||
&& psiField.hasModifierProperty(PsiModifier.STATIC) == fieldStatic
|
||||
&& variableDefinitelyAssignedIn(field, psiField)
|
||||
&& variableDefinitelyAssignedIn(field, psiField, true)
|
||||
&& condition.test(psiField)) {
|
||||
return true;
|
||||
}
|
||||
@@ -214,8 +214,7 @@ public final class HighlightControlFlowUtil {
|
||||
JavaHighlightUtil.visitConstructorChain(constructor, info);
|
||||
if (info.recursivelyCalledConstructor == null) return false;
|
||||
// our constructor is reached from some other constructor by constructor chain
|
||||
return info.visitedConstructors.indexOf(info.recursivelyCalledConstructor) <=
|
||||
info.visitedConstructors.indexOf(constructor);
|
||||
return info.visitedConstructors.indexOf(info.recursivelyCalledConstructor) <= info.visitedConstructors.indexOf(constructor);
|
||||
}
|
||||
|
||||
public static boolean isAssigned(@NotNull PsiParameter parameter) {
|
||||
@@ -246,22 +245,26 @@ public final class HighlightControlFlowUtil {
|
||||
* @return true if variable assigned (maybe more than once)
|
||||
*/
|
||||
public static boolean variableDefinitelyAssignedIn(@NotNull PsiVariable variable, @NotNull PsiElement context) {
|
||||
return variableDefinitelyAssignedIn(variable, context, false);
|
||||
}
|
||||
|
||||
private static boolean variableDefinitelyAssignedIn(@NotNull PsiVariable variable,
|
||||
@NotNull PsiElement context,
|
||||
boolean resultOnIncompleteCode) {
|
||||
try {
|
||||
ControlFlow controlFlow = getControlFlow(context);
|
||||
return ControlFlowUtil.isVariableDefinitelyAssigned(variable, controlFlow);
|
||||
return ControlFlowUtil.isVariableDefinitelyAssigned(variable, getControlFlow(context));
|
||||
}
|
||||
catch (AnalysisCanceledException e) {
|
||||
return false;
|
||||
return resultOnIncompleteCode;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean variableDefinitelyNotAssignedIn(@NotNull PsiVariable variable, @NotNull PsiElement context) {
|
||||
try {
|
||||
ControlFlow controlFlow = getControlFlow(context);
|
||||
return ControlFlowUtil.isVariableDefinitelyNotAssigned(variable, controlFlow);
|
||||
return ControlFlowUtil.isVariableDefinitelyNotAssigned(variable, getControlFlow(context));
|
||||
}
|
||||
catch (AnalysisCanceledException e) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,8 +279,7 @@ public final class HighlightControlFlowUtil {
|
||||
PsiCodeBlock body = canonicalConstructor.getBody();
|
||||
if (body == null) return null;
|
||||
PsiField field = JavaPsiRecordUtil.getFieldForComponent(component);
|
||||
if (field == null) return null;
|
||||
if (variableDefinitelyAssignedIn(field, body)) return null;
|
||||
if (field == null || variableDefinitelyAssignedIn(field, body, true)) return null;
|
||||
String description = JavaErrorBundle.message("record.component.not.initialized", field.getName());
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(description);
|
||||
}
|
||||
@@ -360,7 +362,7 @@ public final class HighlightControlFlowUtil {
|
||||
//if (startOffset < redirectedConstructor.getTextRange().getStartOffset()) continue;
|
||||
if (JavaPsiRecordUtil.isCompactConstructor(redirectedConstructor)) return null;
|
||||
PsiCodeBlock body = redirectedConstructor.getBody();
|
||||
if (body != null && variableDefinitelyAssignedIn(variable, body)) {
|
||||
if (body != null && variableDefinitelyAssignedIn(variable, body, true)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -430,8 +432,7 @@ public final class HighlightControlFlowUtil {
|
||||
// variable referenced in field initializer or in class initializer
|
||||
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 (initializer.hasModifierProperty(PsiModifier.STATIC) == variable.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
if (variableDefinitelyAssignedIn(variable, body)) return null;
|
||||
}
|
||||
}
|
||||
@@ -569,9 +570,8 @@ public final class HighlightControlFlowUtil {
|
||||
|
||||
if (!isFieldStatic) {
|
||||
// constructor that delegates to another constructor cannot assign final fields
|
||||
if (enclosingConstructorOrInitializer instanceof PsiMethod) {
|
||||
PsiMethodCallExpression chainedCall =
|
||||
JavaPsiConstructorUtil.findThisOrSuperCallInConstructor((PsiMethod)enclosingConstructorOrInitializer);
|
||||
if (enclosingConstructorOrInitializer instanceof PsiMethod method) {
|
||||
PsiMethodCallExpression chainedCall = JavaPsiConstructorUtil.findThisOrSuperCallInConstructor(method);
|
||||
if (JavaPsiConstructorUtil.isChainedConstructorCall(chainedCall)) {
|
||||
return true;
|
||||
}
|
||||
@@ -676,7 +676,7 @@ public final class HighlightControlFlowUtil {
|
||||
|
||||
private static boolean canWriteToFinal(@NotNull PsiVariable variable,
|
||||
@NotNull PsiExpression expression,
|
||||
@NotNull PsiReferenceExpression reference,
|
||||
@NotNull PsiReferenceExpression reference,
|
||||
@NotNull PsiFile containingFile) {
|
||||
if (variable.hasInitializer()) {
|
||||
return variable instanceof PsiField field && !PsiAugmentProvider.canTrustFieldInitializer(field);
|
||||
@@ -686,12 +686,15 @@ public final class HighlightControlFlowUtil {
|
||||
if (variable instanceof PsiField field) {
|
||||
// if inside some field initializer
|
||||
if (HighlightUtil.findEnclosingFieldInitializer(expression) != null) return true;
|
||||
PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass == null) return true;
|
||||
// assignment from within inner class is illegal always
|
||||
if (scope != null && !containingFile.getManager().areElementsEquivalent(scope, field.getContainingClass())) return false;
|
||||
if (scope != null && !containingFile.getManager().areElementsEquivalent(scope, containingClass)) return false;
|
||||
PsiMember enclosingCtrOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expression);
|
||||
return enclosingCtrOrInitializer != null &&
|
||||
!(enclosingCtrOrInitializer instanceof PsiMethod &&
|
||||
JavaPsiRecordUtil.isCompactConstructor((PsiMethod)enclosingCtrOrInitializer)) &&
|
||||
!(enclosingCtrOrInitializer instanceof PsiMethod method &&
|
||||
JavaPsiRecordUtil.isCompactConstructor(method) &&
|
||||
containingClass.isRecord()) &&
|
||||
isSameField(enclosingCtrOrInitializer, field, reference, containingFile);
|
||||
}
|
||||
if (variable instanceof PsiLocalVariable) {
|
||||
|
||||
@@ -18,4 +18,20 @@ class TestStaticBlockFinalInitializer {
|
||||
XYZ_AFTER = BAR;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
class Initialize {
|
||||
final int a;
|
||||
final int b;
|
||||
final int c;
|
||||
|
||||
{
|
||||
c = 3;
|
||||
System.out.println(c.<error descr="Identifier expected">)</error>;
|
||||
}
|
||||
|
||||
Initialize () {
|
||||
a = 1;
|
||||
b = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,3 +80,16 @@ record DelegateInitializesField(int n) {
|
||||
System.out.println(n);
|
||||
}
|
||||
}
|
||||
record BrokenRecord(int x, int y) {
|
||||
BrokenRecord(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
<error descr="Unexpected token">.</error>
|
||||
}
|
||||
}
|
||||
class NonRecord {
|
||||
final int a;
|
||||
<error descr="Parameter list expected">NonRecord</error> {
|
||||
a = 10;
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class MutabilityJdk {
|
||||
}
|
||||
|
||||
static class IncompleteCode {
|
||||
<error descr="Variable 'list' might not have been initialized">final List<String> list</error>;
|
||||
final List<String> list;
|
||||
|
||||
IncompleteCode() {
|
||||
list = (IncompleteCode)((<error descr="Expression expected">)</error><error descr="')' expected"><error descr="';' expected">b</error></error>ar()<error descr="';' expected"><error descr="Unexpected token">)</error></error><error descr="Unexpected token">.</error><error descr="Cannot resolve method 'baz' in 'IncompleteCode'">baz</error>();
|
||||
|
||||
Reference in New Issue
Block a user