From 0906b83847f6550f8e14a242558743c825a650d3 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 8 Feb 2017 16:08:23 +0100 Subject: [PATCH] dfa: assume fields used before initialization are null (IDEA-110297) --- .../dataFlow/value/DfaExpressionFactory.java | 15 +++++++++++++++ .../fixture/FieldUsedBeforeInitialization.java | 14 ++++++++++++++ .../fixture/ImplicitlyInitializedField.java | 2 +- .../codeInspection/DataFlowInspectionTest.java | 2 ++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/FieldUsedBeforeInitialization.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java index 7d9ecdb76f7e..b336d42c2759 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.JavaConstantExpressionEvaluator; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -132,6 +133,10 @@ public class DfaExpressionFactory { } if (DfaValueFactory.isEffectivelyUnqualified(refExpr)) { + if (isFieldDereferenceBeforeInitialization(refExpr)) { + return myFactory.getConstFactory().getNull(); + } + return myFactory.getVarFactory().createVariableValue(var, refExpr.getType(), false, null); } @@ -145,6 +150,16 @@ public class DfaExpressionFactory { return myFactory.createTypeValue(type, DfaPsiUtil.getElementNullability(type, var)); } + private static boolean isFieldDereferenceBeforeInitialization(PsiReferenceExpression ref) { + PsiField placeField = PsiTreeUtil.getParentOfType(ref, PsiField.class, true, PsiClass.class, PsiLambdaExpression.class); + if (placeField == null) return false; + + PsiElement target = ref.resolve(); + return target instanceof PsiField && + placeField.getContainingClass() == ((PsiField)target).getContainingClass() && + ((PsiField)target).getInitializer() == null; + } + @Nullable private static PsiModifierListOwner getAccessedVariableOrGetter(final PsiElement target) { if (target instanceof PsiVariable) { diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FieldUsedBeforeInitialization.java b/java/java-tests/testData/inspection/dataFlow/fixture/FieldUsedBeforeInitialization.java new file mode 100644 index 000000000000..dff3eda945b1 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FieldUsedBeforeInitialization.java @@ -0,0 +1,14 @@ +class Foo { + String field; + String field2 = field.substring(1); + int field3 = field2.length(); + Runnable r = new Runnable() { + public void run() { + System.out.println(field.hashCode()); + } + }; + + Foo() { + field = "x"; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ImplicitlyInitializedField.java b/java/java-tests/testData/inspection/dataFlow/fixture/ImplicitlyInitializedField.java index 0010c39a6772..b8b9a28972e2 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ImplicitlyInitializedField.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ImplicitlyInitializedField.java @@ -1,7 +1,7 @@ class Foo { String field; String field2; - int hash = field.hashCode(); + int hash = field.hashCode(); Foo(String f2) { field2 = f2; diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index d68abce179b9..5da2b3f67dc5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -421,6 +421,8 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { public void testDivisionByZero() { doTestReportConstantReferences(); } + public void testFieldUsedBeforeInitialization() { doTest(); } + public void testImplicitlyInitializedField() { PlatformTestUtil.registerExtension(ImplicitUsageProvider.EP_NAME, new ImplicitUsageProvider() { @Override