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 b6efb5baaa8e..2522ce7cd82c 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 @@ -20,7 +20,6 @@ import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInspection.dataFlow.instructions.Instruction; import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction; import com.intellij.codeInspection.dataFlow.instructions.ReturnInstruction; -import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.util.Ref; import com.intellij.patterns.PsiJavaPatterns; @@ -32,6 +31,7 @@ import com.intellij.psi.util.*; import com.intellij.util.ArrayUtil; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.JBIterable; import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NotNull; @@ -220,21 +220,34 @@ public class DfaPsiUtil { PsiCall call = ((MethodCallInstruction)instruction).getCallExpression(); if (call == null) return false; - if (call instanceof PsiMethodCallExpression && - DfaValueFactory.isEffectivelyUnqualified(((PsiMethodCallExpression)call).getMethodExpression())) { + if (call instanceof PsiNewExpression && canAccessFields((PsiExpression)call)) { return true; } + if (call instanceof PsiMethodCallExpression) { + PsiExpression qualifier = ((PsiMethodCallExpression)call).getMethodExpression().getQualifierExpression(); + if (qualifier == null || canAccessFields(qualifier)) { + return true; + } + } + PsiExpressionList argumentList = call.getArgumentList(); if (argumentList != null) { for (PsiExpression expression : argumentList.getExpressions()) { - if (expression instanceof PsiThisExpression) return true; + if (canAccessFields(expression)) return true; } } return false; } + private boolean canAccessFields(PsiExpression expression) { + PsiClass type = PsiUtil.resolveClassInClassTypeOnly(expression.getType()); + JBIterable typeContainers = + JBIterable.generate(type, PsiClass::getContainingClass).takeWhile(c -> !c.hasModifierProperty(PsiModifier.STATIC)); + return typeContainers.contains(containingClass); + } + @NotNull @Override protected DfaInstructionState[] acceptInstruction(@NotNull InstructionVisitor visitor, @NotNull DfaInstructionState instructionState) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java index 8b459a164614..40cdd2db96c8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java @@ -189,30 +189,26 @@ public class DfaVariableValue extends DfaValue { } if (var instanceof PsiField && DfaPsiUtil.isFinalField((PsiVariable)var) && myFactory.isHonorFieldInitializers()) { + PsiExpression initializer = ((PsiField)var).getInitializer(); + if (initializer != null) { + return getFieldInitializerNullness(initializer); + } + List initializers = DfaPsiUtil.findAllConstructorInitializers((PsiField)var); if (initializers.isEmpty()) { return defaultNullability; } - boolean hasUnknowns = false; for (PsiExpression expression : initializers) { - Nullness nullness = getFieldInitializerNullness(expression); - if (nullness == Nullness.NULLABLE) { + if (getFieldInitializerNullness(expression) == Nullness.NULLABLE) { return Nullness.NULLABLE; } - if (nullness == Nullness.UNKNOWN) { - hasUnknowns = true; - } } - - if (hasUnknowns) { - if (DfaPsiUtil.isInitializedNotNull((PsiField)var)) { - return Nullness.NOT_NULL; - } - return defaultNullability; + + if (DfaPsiUtil.isInitializedNotNull((PsiField)var)) { + return Nullness.NOT_NULL; } - - return Nullness.NOT_NULL; + return defaultNullability; } return defaultNullability; @@ -223,11 +219,11 @@ public class DfaVariableValue extends DfaValue { if (expression instanceof PsiNewExpression || expression instanceof PsiLiteralExpression || expression instanceof PsiPolyadicExpression) return Nullness.NOT_NULL; if (expression instanceof PsiReferenceExpression) { PsiElement target = ((PsiReferenceExpression)expression).resolve(); - return DfaPsiUtil.getElementNullability(null, (PsiModifierListOwner)target); + return DfaPsiUtil.getElementNullability(expression.getType(), (PsiModifierListOwner)target); } if (expression instanceof PsiMethodCallExpression) { PsiMethod method = ((PsiMethodCallExpression)expression).resolveMethod(); - return method != null ? DfaPsiUtil.getElementNullability(null, method) : Nullness.UNKNOWN; + return method != null ? DfaPsiUtil.getElementNullability(expression.getType(), method) : Nullness.UNKNOWN; } return Nullness.UNKNOWN; } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FinalFieldInCallBeforeInitialization.java b/java/java-tests/testData/inspection/dataFlow/fixture/FinalFieldInCallBeforeInitialization.java new file mode 100644 index 000000000000..1ac41e6bb043 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FinalFieldInCallBeforeInitialization.java @@ -0,0 +1,20 @@ +class FailingNonNull { + private final String nullable; + + public FailingNonNull() { + Inner inner = new Inner(); + inner.doNullableStuff(); + nullable = "now non-null"; + } + + private class Inner{ + public void doNullableStuff() { + if (nullable !=null) { //Condition 'nullable!=null' is always 'true' + System.out.println(nullable.length()); + } + } + } + public static void main(String[] args) { + new FailingNonNull(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index 4987d0a8c5ab..a661955992af 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -193,6 +193,7 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { public void testRememberLocalTransientFieldState() { doTest(); } public void testFinalFieldDuringInitialization() { doTest(); } public void testFinalFieldDuringSuperInitialization() { doTest(); } + public void testFinalFieldInCallBeforeInitialization() { doTest(); } public void testFinalFieldInConstructorAnonymous() { doTest(); } public void testFinalFieldNotDuringInitialization() {