summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorAyushman Jain2011-12-14 18:20:13 (EST)
committer Stephan Herrmann2011-12-16 08:58:46 (EST)
commita1c831accbe1d013566d961396c6adfb5c4fb365 (patch)
tree24686da90319e1aa4233753341e812873f74aaf2
parentfda975d98b069f678ae89a663957463bb7bd4088 (diff)
downloadeclipse.jdt.core-a1c831accbe1d013566d961396c6adfb5c4fb365.zip
eclipse.jdt.core-a1c831accbe1d013566d961396c6adfb5c4fb365.tar.gz
eclipse.jdt.core-a1c831accbe1d013566d961396c6adfb5c4fb365.tar.bz2
Fix v1.2.1
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java16
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java32
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java608
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java20
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java26
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java15
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java7
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java14
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java16
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java9
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java50
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java44
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java93
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java28
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java194
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java102
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java66
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java260
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java28
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java12
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java153
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties10
-rw-r--r--org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java2
28 files changed, 1421 insertions, 413 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index 95fa1b1..670e436 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -724,6 +724,7 @@ public void test011_problem_categories() {
expectedProblemAttributes.put("NonGenericConstructor", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("NonGenericMethod", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("NonGenericType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+ expectedProblemAttributes.put("NonNullFieldComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NonNullLocalVariableComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NonStaticAccessToStaticField", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE));
expectedProblemAttributes.put("NonStaticAccessToStaticMethod", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE));
@@ -736,6 +737,9 @@ public void test011_problem_categories() {
expectedProblemAttributes.put("NotVisibleField", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
expectedProblemAttributes.put("NotVisibleMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
expectedProblemAttributes.put("NotVisibleType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+ expectedProblemAttributes.put("NullFieldComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("NullFieldInstanceofYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("NullFieldReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NullLocalVariableComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NullLocalVariableInstanceofYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NullLocalVariableReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
@@ -779,6 +783,7 @@ public void test011_problem_categories() {
expectedProblemAttributes.put("PotentialHeapPollutionFromVararg", new ProblemAttributes(CategorizedProblem.CAT_UNCHECKED_RAW));
expectedProblemAttributes.put("PotentiallyUnclosedCloseable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("PotentiallyUnclosedCloseableAtExit", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("PotentialNullFieldReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("PotentialNullLocalVariableReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("PotentialNullMessageSendReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("PublicClassMustMatchFileName", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
@@ -788,10 +793,13 @@ public void test011_problem_categories() {
expectedProblemAttributes.put("RedefinedArgument", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
expectedProblemAttributes.put("RedefinedLocal", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
expectedProblemAttributes.put("RedundantSpecificationOfTypeArguments", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE));
+ expectedProblemAttributes.put("RedundantFieldNullAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("RedundantLocalVariableNullAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("RedundantNullAnnotation", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE));
+ expectedProblemAttributes.put("RedundantNullCheckOnNonNullField", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("RedundantNullCheckOnNonNullLocalVariable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("RedundantNullCheckOnNonNullMessageSend", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("RedundantNullCheckOnNullField", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("RedundantNullCheckOnNullLocalVariable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("RedundantSuperinterface", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE));
expectedProblemAttributes.put("ReferenceToForwardField", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
@@ -1414,6 +1422,7 @@ public void test012_compiler_problems_tuning() {
expectedProblemAttributes.put("NonGenericConstructor", SKIP);
expectedProblemAttributes.put("NonGenericMethod", SKIP);
expectedProblemAttributes.put("NonGenericType", SKIP);
+ expectedProblemAttributes.put("NonNullFieldComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("NonNullLocalVariableComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("NonStaticAccessToStaticField", new ProblemAttributes(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER));
expectedProblemAttributes.put("NonStaticAccessToStaticMethod", new ProblemAttributes(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER));
@@ -1426,6 +1435,9 @@ public void test012_compiler_problems_tuning() {
expectedProblemAttributes.put("NotVisibleField", SKIP);
expectedProblemAttributes.put("NotVisibleMethod", SKIP);
expectedProblemAttributes.put("NotVisibleType", SKIP);
+ expectedProblemAttributes.put("NullFieldComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
+ expectedProblemAttributes.put("NullFieldInstanceofYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
+ expectedProblemAttributes.put("NullFieldReference", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_REFERENCE));
expectedProblemAttributes.put("NullLocalVariableComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("NullLocalVariableInstanceofYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("NullLocalVariableReference", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_REFERENCE));
@@ -1469,6 +1481,7 @@ public void test012_compiler_problems_tuning() {
expectedProblemAttributes.put("PotentialHeapPollutionFromVararg", new ProblemAttributes(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION));
expectedProblemAttributes.put("PotentiallyUnclosedCloseable", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE));
expectedProblemAttributes.put("PotentiallyUnclosedCloseableAtExit", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE));
+ expectedProblemAttributes.put("PotentialNullFieldReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE));
expectedProblemAttributes.put("PotentialNullLocalVariableReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE));
expectedProblemAttributes.put("PotentialNullMessageSendReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE));
expectedProblemAttributes.put("PublicClassMustMatchFileName", SKIP);
@@ -1478,10 +1491,13 @@ public void test012_compiler_problems_tuning() {
expectedProblemAttributes.put("RedefinedArgument", SKIP);
expectedProblemAttributes.put("RedefinedLocal", SKIP);
expectedProblemAttributes.put("RedundantSpecificationOfTypeArguments", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_TYPE_ARGUMENTS));
+ expectedProblemAttributes.put("RedundantFieldNullAssignment", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("RedundantLocalVariableNullAssignment", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("RedundantNullAnnotation", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_ANNOTATION));
+ expectedProblemAttributes.put("RedundantNullCheckOnNonNullField", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("RedundantNullCheckOnNonNullLocalVariable", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("RedundantNullCheckOnNonNullMessageSend", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
+ expectedProblemAttributes.put("RedundantNullCheckOnNullField", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("RedundantNullCheckOnNullLocalVariable", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("RedundantSuperinterface", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_SUPERINTERFACE));
expectedProblemAttributes.put("ReferenceToForwardField", SKIP);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java
index 95af131..047f5f5 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java
@@ -34,9 +34,11 @@ import org.eclipse.jdt.internal.compiler.flow.NullInfoRegistry;
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo.AssertionFailedException;
import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
/**
* A tests series especially meant to validate the internals of our null
@@ -1083,18 +1085,36 @@ public FlowInfo copy() {
return copy;
}
-public void markAsDefinitelyNonNull(LocalVariableBinding local) {
- grow(local.id + this.maxFieldCount);
+public void markAsDefinitelyNonNull(VariableBinding local) {
+ int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ grow(position);
super.markAsDefinitelyNonNull(local);
}
-public void markAsDefinitelyNull(LocalVariableBinding local) {
- grow(local.id + this.maxFieldCount);
+public void markAsDefinitelyNull(VariableBinding local) {
+ int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ grow(position);
super.markAsDefinitelyNull(local);
}
-public void markAsDefinitelyUnknown(LocalVariableBinding local) {
- grow(local.id + this.maxFieldCount);
+public void markAsDefinitelyUnknown(VariableBinding local) {
+ int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ grow(position);
super.markAsDefinitelyUnknown(local);
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java
index 2349a4b..4997fb0 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java
@@ -108,13 +108,12 @@ public void test0002_simple_field() {
" o.toString();\n" +
" }\n" +
"}\n"},
- ""
-// "----------\n" +
-// "1. ERROR in X.java (at line 5)\n" +
-// " o.toString();\n" +
-// " ^\n" +
-// "The field o is likely null; it was either set to null or checked for null when last used\n" +
-// "----------\n"
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
);
}
@@ -345,13 +344,12 @@ public void test0014_field_with_explicit_this_access() {
" this.o.toString();\n" +
" }\n" +
"}\n"},
- ""
-// "----------\n" +
-// "1. ERROR in X.java (at line 5)\n" +
-// " this.o.toString();\n" +
-// " ^^^^^^\n" +
-// "The field o is likely null; it was either set to null or checked for null when last used\n" +
-// "----------\n"
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " this.o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
);
}
@@ -367,13 +365,12 @@ public void test0015_field_with_explicit_this_access() {
" o.toString();\n" +
" }\n" +
"}\n"},
- ""
-// "----------\n" +
-// "1. ERROR in X.java (at line 5)\n" +
-// " o.toString();\n" +
-// " ^\n" +
-// "The field o is likely null; it was either set to null or checked for null when last used\n" +
-// "----------\n"
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
);
}
@@ -423,13 +420,12 @@ public void test0018_field_of_enclosing_object() {
" }\n" +
" }\n" +
"}\n"},
- ""
-// "----------\n" +
-// "1. ERROR in X.java (at line 6)\n" +
-// " X.this.o.toString();\n" +
-// " ^^^^^^^^\n" +
-// "The field o is likely null; it was either set to null or checked for null when last used\n" +
-// "----------\n"
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " X.this.o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
);
}
@@ -448,13 +444,12 @@ public void test0019_field_synchronized() {
" }\n" +
" void bar() {/* */}\n" +
"}\n"},
- ""
-// "----------\n" +
-// "1. ERROR in X.java (at line 5)\n" +
-// " o.toString();\n" +
-// " ^\n" +
-// "The field o is likely null; it was either set to null or checked for null when last used\n" +
-// "----------\n"
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
);
}
@@ -15425,4 +15420,547 @@ public void testBug360328d() {
"",/* expected error */
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
}
+
+// null analysis -- simple case for field
+public void testBug247564a() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object o;\n" +
+ " void foo() {\n" +
+ " if (o == null && o.toString() == \"\"){}\n" +
+ " else {}\n" +
+ " o.toString();\n" + // toString() call above defuses null info, so no warning here
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 4)\n" +
+ " if (o == null && o.toString() == \"\"){}\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- simple case for field
+// no redundant null check warnings should be obtained since value of field
+// may be changed in another thread.
+public void testBug247564a_1() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object o;\n" +
+ " void foo() {\n" +
+ " o = null;" +
+ " if (o == null){}\n" +
+ " if (o != null){}\n" +
+ " o.toString();\n" + // warn here
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- simple case for field
+public void testBug247564a_2() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object o;\n" +
+ " void foo() {\n" +
+ " if (o == null){\n" + // o is null inside the if block
+ " o.toString();\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- simple case for field
+// null info from one method should not be present in the other (for instance fields)
+public void testBug247564a_3() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object o;\n" +
+ " void foo() {\n" +
+ " }\n" +
+ " void foo1() {\n" +
+ " o.toString();\n" +
+ " }\n" +
+ "}\n"},
+ ""
+ );
+}
+
+// null analysis -- simple case for static final field
+public void testBug247564b() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " static final Object o = null;\n" +
+ " static final Object o1 = new Object();\n" +
+ " void foo() {\n" +
+ " if (o.toString() == \"\") {}\n" +
+ " if (o == null) {}\n" +
+ " if (o != null) {}\n" +
+ " if (o1 == null) {}\n" +
+ " if (o1 != null) {}\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " if (o.toString() == \"\") {}\n" +
+ " ^\n" +
+ "Null pointer access: The field o can only be null at this location\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 6)\n" +
+ " if (o == null) {}\n" +
+ " ^\n" +
+ "Redundant null check: The field o can only be null at this location\n" +
+ "----------\n" +
+ "3. ERROR in X.java (at line 7)\n" +
+ " if (o != null) {}\n" +
+ " ^\n" +
+ "Null comparison always yields false: The field o can only be null at this location\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 7)\n" +
+ " if (o != null) {}\n" +
+ " ^^\n" +
+ "Dead code\n" +
+ "----------\n" +
+ "5. ERROR in X.java (at line 8)\n" +
+ " if (o1 == null) {}\n" +
+ " ^^\n" +
+ "Null comparison always yields false: The field o1 cannot be null at this location\n" +
+ "----------\n" +
+ "6. WARNING in X.java (at line 8)\n" +
+ " if (o1 == null) {}\n" +
+ " ^^\n" +
+ "Dead code\n" +
+ "----------\n" +
+ "7. ERROR in X.java (at line 9)\n" +
+ " if (o1 != null) {}\n" +
+ " ^^\n" +
+ "Redundant null check: The field o1 cannot be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- simple case for static final field
+public void testBug247564b_1() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " static final Object o;\n" +
+ " static final Object o1;\n" +
+ " static {\n" +
+ " o = null;\n" +
+ " o1 = new Object();\n" +
+ " }\n" +
+ " void foo() {\n" +
+ " if (o.toString() == \"\") {}\n" +
+ " if (o == null) {}\n" +
+ " if (o != null) {}\n" +
+ " if (o1 == null) {}\n" +
+ " if (o1 != null) {}\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 9)\n" +
+ " if (o.toString() == \"\") {}\n" +
+ " ^\n" +
+ "Null pointer access: The field o can only be null at this location\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 10)\n" +
+ " if (o == null) {}\n" +
+ " ^\n" +
+ "Redundant null check: The field o can only be null at this location\n" +
+ "----------\n" +
+ "3. ERROR in X.java (at line 11)\n" +
+ " if (o != null) {}\n" +
+ " ^\n" +
+ "Null comparison always yields false: The field o can only be null at this location\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 11)\n" +
+ " if (o != null) {}\n" +
+ " ^^\n" +
+ "Dead code\n" +
+ "----------\n" +
+ "5. ERROR in X.java (at line 12)\n" +
+ " if (o1 == null) {}\n" +
+ " ^^\n" +
+ "Null comparison always yields false: The field o1 cannot be null at this location\n" +
+ "----------\n" +
+ "6. WARNING in X.java (at line 12)\n" +
+ " if (o1 == null) {}\n" +
+ " ^^\n" +
+ "Dead code\n" +
+ "----------\n" +
+ "7. ERROR in X.java (at line 13)\n" +
+ " if (o1 != null) {}\n" +
+ " ^^\n" +
+ "Redundant null check: The field o1 cannot be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- fields in synchronized methods
+// check that null analysis for fields in synchronized methods
+// behave as it does in ordinary methods.
+public void testBug247564c() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object o;\n" +
+ " Object o1;\n" +
+ " static final Object o2 = null;\n" +
+ " static final Object o3 = new Object();\n" +
+ " synchronized void foo() {\n" +
+ " o = null;\n" +
+ " if (o == null) {\n" +
+ " o.toString();\n" +
+ " }\n" +
+ " o1 = new Object();\n" +
+ " if (o1 == null) {\n" +
+ " o1.toString();\n" +
+ " }\n" +
+ " if (o2 != null) {\n" +
+ " }\n" +
+ " else {\n" +
+ " o2.toString();\n" +
+ " }\n" +
+ " if (o3 == null) {\n" +
+ " }\n" +
+ " else {\n" +
+ " o3.toString();\n" +
+ " }\n" +
+ " }\n" +
+ " void foo1() {\n" +
+ " o.toString();\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 9)\n" +
+ " o.toString();\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 13)\n" +
+ " o1.toString();\n" +
+ " ^^\n" +
+ "Potential null pointer access: The field o1 may be null at this location\n" +
+ "----------\n" +
+ "3. ERROR in X.java (at line 15)\n" +
+ " if (o2 != null) {\n" +
+ " ^^\n" +
+ "Null comparison always yields false: The field o2 can only be null at this location\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 15)\n" +
+ " if (o2 != null) {\n" +
+ " }\n" +
+ " ^^^^^\n" +
+ "Dead code\n" +
+ "----------\n" +
+ "5. ERROR in X.java (at line 18)\n" +
+ " o2.toString();\n" +
+ " ^^\n" +
+ "Null pointer access: The field o2 can only be null at this location\n" +
+ "----------\n" +
+ "6. ERROR in X.java (at line 20)\n" +
+ " if (o3 == null) {\n" +
+ " ^^\n" +
+ "Null comparison always yields false: The field o3 cannot be null at this location\n" +
+ "----------\n" +
+ "7. WARNING in X.java (at line 20)\n" +
+ " if (o3 == null) {\n" +
+ " }\n" +
+ " ^^^^^\n" +
+ "Dead code\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- test redundant instanceof warning for static final field
+public void testBug247564d() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " static final Object o = null;\n" +
+ " static final Object o1 = new Object();\n" +
+ " void foo() {\n" +
+ " if (o instanceof String) {}\n" +
+ " if (o1 instanceof String) {}\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 5)\n" +
+ " if (o instanceof String) {}\n" +
+ " ^\n" +
+ "instanceof always yields false: The field o can only be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- test redundant instanceof warning for static final fields
+public void testBug247564e_1() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " static final Object o = null;\n" +
+ " void foo() {\n" +
+ " if (o instanceof X) return;\n" +
+ " }\n" +
+ "}"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 4)\n" +
+ " if (o instanceof X) return;\n" +
+ " ^\n" +
+ "instanceof always yields false: The field o can only be null at this location\n" +
+ "----------\n",
+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
+}
+
+// null analysis -- test potential null ptr access warning because of static field access through object returned by method call
+public void testBug247564f() {
+ Map compilerOptions = getCompilerOptions();
+ compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE);
+ this.runNegativeTest(
+ false,
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " static Object o;\n" +
+ " static Object o1;\n" +
+ " Object o2;\n" +
+ " X getX() { return new X();\n}\n" +
+ " void foo() {\n" +
+ " if (getX().o == null && this.o.hashCode() == 0) return;\n" +
+ " if (getX().o2 == null && this.o2.hashCode() == 0) return;\n" +
+ " }\n" +
+ "}"},
+ null,
+ compilerOptions,
+ "----------\n" +
+ "1. ERROR in X.java (at line 8)\n" +
+ " if (getX().o == null && this.o.hashCode() == 0) return;\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n",
+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
+}
+
+// null analysis -- test potential null ptr access warning because of static field access through object returned by method call
+public void testBug247564f_1() {
+ Map compilerOptions = getCompilerOptions();
+ compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE);
+ this.runNegativeTest(
+ false,
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " static Object o;\n" +
+ " X getX() { return new X();\n}\n" +
+ " Y getY() { return new Y();\n}\n" +
+ " void foo() {\n" +
+ " if (getY().o == null && this.o.hashCode() == 0) return;\n" +
+ " if (getX().o == null && this.o.hashCode() == 0) return;\n" +
+ " }\n" +
+ "}\n" +
+ "class Y{\n" +
+ " static Object o;\n" +
+ "}\n"},
+ null,
+ compilerOptions,
+ "----------\n" +
+ "1. ERROR in X.java (at line 9)\n" +
+ " if (getX().o == null && this.o.hashCode() == 0) return;\n" +
+ " ^\n" +
+ "Potential null pointer access: The field o may be null at this location\n" +
+ "----------\n",
+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
+}
+
+// null analysis -- test field analysis in case of more than 64 fields
+public void testBug247564g() {
+ Map compilerOptions = getCompilerOptions();
+ compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE);
+ this.runNegativeTest(
+ false,
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ "Object field0, \n" +
+ "field1, field2, field3, field4, \n" +
+ "field5, field6, field7, field8, \n" +
+ "field9, field10, field11, field12, \n" +
+ "field13, field14, field15, field16, \n" +
+ "field17, field18, field19, field20, \n" +
+ "field21, field22, field23, field24, \n" +
+ "field25, field26, field27, field28, \n" +
+ "field29, field30, field31, field32, \n" +
+ "field33, field34, field35, field36, \n" +
+ "field37, field38, field39, field40, \n" +
+ "field41, field42, field43, field44, \n" +
+ "field45, field46, field47, field48, \n" +
+ "field49, field50, field51, field52, \n" +
+ "field53, field54, field55, field56, \n" +
+ "field57, field58, field59, field60, \n" +
+ "field61, field62, field63, field64, \n" +
+ "field65, field66, field67, field68, \n" +
+ "field69, field70, field71, field72, \n" +
+ "field73, field74, field75, field76, \n" +
+ "field77, field78, field79, field80, \n" +
+ "field81, field82, field83, field84, \n" +
+ "field85, field86, field87, field88, \n" +
+ "field89, field90, field91, field92, \n" +
+ "field93, field94, field95, field96, \n" +
+ "field97, field98, field99;\n" +
+ "static final Object field100 = null;\n" +
+ " void foo() {\n" +
+ " int i = 0;" +
+ " while (i<10){\n" +
+ " i++;\n" +
+ " if (this.field99 == null && this.field99.hashCode() == 0){}\n" +
+ " this.field98 = null;\n" +
+ " }\n" +
+ " if (this.field98.hashCode() == 0) {}\n" + // should not complain
+ " this.field97 = null;\n" +
+ " if (this.field97.hashCode() == 0) {}\n" +
+ " if (this.field100.hashCode() == 0) {}\n" +
+ " }\n" +
+ "}"},
+ null,
+ compilerOptions,
+ "----------\n" +
+ "1. ERROR in X.java (at line 32)\n" +
+ " if (this.field99 == null && this.field99.hashCode() == 0){}\n" +
+ " ^^^^^^^\n" +
+ "Potential null pointer access: The field field99 may be null at this location\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 37)\n" +
+ " if (this.field97.hashCode() == 0) {}\n" +
+ " ^^^^^^^\n" +
+ "Potential null pointer access: The field field97 may be null at this location\n" +
+ "----------\n" +
+ "3. ERROR in X.java (at line 38)\n" +
+ " if (this.field100.hashCode() == 0) {}\n" +
+ " ^^^^^^^^\n" +
+ "Null pointer access: The field field100 can only be null at this location\n" +
+ "----------\n",
+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
+}
+
+// null analysis -- simple case for field for inner class
+// to make sure field id's of inner and outer classes are not same for flow analysis
+public void testBug247564h() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object o;\n" +
+ " class X1 {\n" +
+ " Object x;" +
+ " Object x1;" +
+ " Object x2;" +
+ " void goo() {\n" +
+ " if (o == null && x.toString() == \"\"){}\n" +
+ " if (o2 == null && o2.toString() == \"\"){}\n" +
+ " if (o2 == null && x2.toString() == \"\"){}\n" +
+ " }\n" +
+
+ " }\n" +
+ " Object o1;\n" +
+ " static Object o2;\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " if (o2 == null && o2.toString() == \"\"){}\n" +
+ " ^^\n" +
+ "Potential null pointer access: The field o2 may be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- simple case for field for inner class
+// to make sure that id's of local variables in inner classes dotn conflict with those of fields.
+public void testBug247564h_1() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object field0;\n" +
+ " Object field1;\n" +
+ " class X1 {\n" +
+ " Object field2;" +
+ " Object field3;" +
+ " void goo(Object var) {\n" +
+ " if (var == null && field2.toString() == \"\"){}\n" +
+ " if (var == null && field3.toString() == \"\"){}\n" +
+ " if (field2 == null && field2.toString() == \"\"){}\n" +
+ " }\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 8)\n" +
+ " if (field2 == null && field2.toString() == \"\"){}\n" +
+ " ^^^^^^\n" +
+ "Potential null pointer access: The field field2 may be null at this location\n" +
+ "----------\n"
+ );
+}
+
+// null analysis -- simple case for field for inner class
+// to make sure that id's of local variables in inner classes dotn conflict with those of fields.
+public void testBug247564h_2() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " Object field0;\n" +
+ " Object field1;\n" +
+ " class X1 {\n" +
+ " Object field2;\n" +
+ " Object field3;\n" +
+ " class X2 {\n" +
+ " Object field4;\n" +
+ " Object field5;\n" +
+ " void goo(Object var) {\n" +
+ " if (var == null && field4.toString() == \"\"){}\n" +
+ " if (var == null && field5.toString() == \"\"){}\n" +
+ " if (field3 == null && field3.toString() == \"\"){}\n" +
+ " if (field3 == null && field1.toString() == \"\"){}\n" +
+ " }\n" +
+ " }\n" +
+ " Object field22;\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in X.java (at line 13)\n" +
+ " if (field3 == null && field3.toString() == \"\"){}\n" +
+ " ^^^^^^\n" +
+ "Potential null pointer access: The field field3 may be null at this location\n" +
+ "----------\n"
+ );
+}
} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index 6b2f414..d31e466 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -1281,6 +1281,26 @@ void setSourceStart(int sourceStart);
/** @since 3.4 */
int UnusedTypeArgumentsForConstructorInvocation = MethodRelated + 660;
+ /**
+ * Null analysis for fields
+ */
+ /** @since 3.8*/
+ int NullFieldReference = Internal + FieldRelated + 670;
+ /** @since 3.8*/
+ int PotentialNullFieldReference = Internal + FieldRelated + 671;
+ /** @since 3.8*/
+ int RedundantNullCheckOnNullField = Internal + FieldRelated + 672;
+ /** @since 3.8*/
+ int NullFieldComparisonYieldsFalse = Internal + FieldRelated + 673;
+ /** @since 3.8*/
+ int RedundantNullCheckOnNonNullField = Internal + FieldRelated + 674;
+ /** @since 3.8*/
+ int NonNullFieldComparisonYieldsFalse = Internal + FieldRelated + 675;
+ /** @since 3.8*/
+ int RedundantFieldNullAssignment = Internal + FieldRelated + 676;
+ /** @since 3.8*/
+ int NullFieldInstanceofYieldsFalse = Internal + FieldRelated + 677;
+
/**
* Corrupted binaries
*/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
index 970fc24..f527dec 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
@@ -42,14 +42,15 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
// record setting a variable: various scenarii are possible, setting an array reference,
// a field reference, a blank final field reference, a field of an enclosing instance or
// just a local variable.
- LocalVariableBinding local = this.lhs.localVariableBinding();
+ VariableBinding var = this.lhs.variableBinding();
if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
this.expression.checkNPE(currentScope, flowContext, flowInfo);
}
flowInfo = ((Reference) this.lhs)
.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
.unconditionalInits();
- if (local != null) {
+ if (var instanceof LocalVariableBinding) {
+ LocalVariableBinding local = (LocalVariableBinding) var;
LocalVariableBinding previousTrackerBinding = null;
if (local.closeTracker != null) {
// Assigning to a variable already holding an AutoCloseable, has it been closed before?
@@ -60,17 +61,23 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.expression, local, previousTrackerBinding);
}
int nullStatus = this.expression.nullStatus(flowInfo);
- if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
+ if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) {
if (nullStatus == FlowInfo.NULL) {
- flowContext.recordUsingNullReference(currentScope, local, this.lhs,
+ flowContext.recordUsingNullReference(currentScope, var, this.lhs,
FlowContext.CAN_ONLY_NULL | FlowContext.IN_ASSIGNMENT, flowInfo);
}
}
- nullStatus = checkAssignmentAgainstNullAnnotation(currentScope, flowContext, local, nullStatus, this.expression);
- if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
- flowInfo.markNullStatus(local, nullStatus);
+ nullStatus = checkAssignmentAgainstNullAnnotation(currentScope, flowContext, var, nullStatus, this.expression);
+ if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) {
+ flowInfo.markNullStatus(var, nullStatus);
if (flowContext.initsOnFinally != null)
- flowContext.initsOnFinally.markNullStatus(local, nullStatus);
+ flowContext.initsOnFinally.markNullStatus(var, nullStatus);
+ if (var instanceof FieldBinding && var.isFinal() && ((FieldBinding) var).isStatic()) {
+ // static final field being assigned. Record its null status for future reference
+ // since the flowInfo from a constructor or static block wont be available in a method
+ FieldBinding fieldBinding = (FieldBinding) var;
+ fieldBinding.setNullStatusForStaticFinalField(nullStatus);
+ }
}
return flowInfo;
}
@@ -224,4 +231,7 @@ public void traverse(ASTVisitor visitor, BlockScope scope) {
public LocalVariableBinding localVariableBinding() {
return this.lhs.localVariableBinding();
}
+public VariableBinding variableBinding() {
+ return this.lhs.variableBinding();
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
index 90b2f96..daf54e4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
@@ -37,6 +37,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo);
}
}
+ // don't let the flow info collected for fields from this block persist.
+ flowInfo.resetNullInfoForFields();
if (this.explicitDeclarations > 0) // if block has its own scope analyze tracking vars now:
this.scope.checkUnclosedCloseables(flowInfo, null, null);
return flowInfo;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
index 396276a..2be8077 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -33,6 +33,7 @@ import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
public class CastExpression extends Expression {
@@ -445,6 +446,13 @@ public LocalVariableBinding localVariableBinding() {
return this.expression.localVariableBinding();
}
+/**
+ * @see org.eclipse.jdt.internal.compiler.ast.Expression#variableBinding()
+ */
+public VariableBinding variableBinding() {
+ return this.expression.variableBinding();
+}
+
public int nullStatus(FlowInfo flowInfo) {
return this.expression.nullStatus(flowInfo);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
index e521d40..ae49e8c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
@@ -39,16 +39,16 @@ public class EqualExpression extends BinaryExpression {
// TODO: handle all kinds of expressions (cf. also https://bugs.eclipse.org/364326)
}
- LocalVariableBinding local = this.left.localVariableBinding();
+ VariableBinding local = this.left.variableBinding();
if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, rightStatus, this.left);
}
- local = this.right.localVariableBinding();
+ local = this.right.variableBinding();
if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, leftStatus, this.right);
}
}
- private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) {
+ private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, VariableBinding local, int nullStatus, Expression reference) {
switch (nullStatus) {
case FlowInfo.NULL :
if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index df21615..7512e3f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -36,6 +36,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
import org.eclipse.jdt.internal.compiler.util.Messages;
@@ -525,14 +526,14 @@ public final boolean checkCastTypesCompatibility(Scope scope, TypeBinding castTy
* @param flowInfo the upstream flow info; caveat: may get modified
*/
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
- LocalVariableBinding local = localVariableBinding();
+ VariableBinding local = variableBinding();
if (local != null &&
(local.type.tagBits & TagBits.IsBaseType) == 0) {
if ((this.bits & ASTNode.IsNonNull) == 0) {
flowContext.recordUsingNullReference(scope, local, this,
FlowContext.MAY_NULL, flowInfo);
}
- flowInfo.markAsComparedEqualToNonNull(local);
+ flowInfo.markAsComparedEqualToNonNull(local );
// from thereon it is set
if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
flowInfo.markedAsNullOrNonNullInAssertExpression(local);
@@ -872,7 +873,7 @@ public int nullStatus(FlowInfo flowInfo) {
this.constant != null && this.constant != Constant.NotAConstant)
return FlowInfo.NON_NULL; // constant expression cannot be null
- LocalVariableBinding local = localVariableBinding();
+ VariableBinding local = variableBinding();
if (local != null)
return flowInfo.nullStatus(local);
return FlowInfo.NON_NULL;
@@ -1112,4 +1113,12 @@ public void traverse(ASTVisitor visitor, BlockScope scope) {
public void traverse(ASTVisitor visitor, ClassScope scope) {
// nothing to do
}
+
+/**
+ * Returns the field or local variable referenced by this node. Can be a direct reference (SingleNameReference)
+ * or thru a cast expression etc...
+ */
+public VariableBinding variableBinding() {
+ return null;
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
index 30ab54e..57d58e3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
@@ -74,6 +74,13 @@ public FlowInfo analyseCode(MethodScope initializationScope, FlowContext flowCon
.analyseCode(initializationScope, flowContext, flowInfo)
.unconditionalInits();
flowInfo.markAsDefinitelyAssigned(this.binding);
+ if (this.binding.isFinal() && this.binding.isStatic()) {
+ int nullStatus = this.initialization.nullStatus(flowInfo);
+ // static final field being initialized. Record its null status for future reference
+ // since the flowInfo from an initialization wont be available in a method
+
+ this.binding.setNullStatusForStaticFinalField(nullStatus);
+ }
}
return flowInfo;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
index 66f16b6..1377d78 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
@@ -35,6 +35,7 @@ import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
public class FieldReference extends Reference implements InvocationSite {
@@ -668,4 +669,17 @@ public void traverse(ASTVisitor visitor, BlockScope scope) {
}
visitor.endVisit(this, scope);
}
+
+public VariableBinding variableBinding() {
+ if (this.receiver.isThis() || this.binding.isStatic()) {
+ if (this.receiver instanceof MessageSend) {
+ if (((MessageSend) this.receiver).actualReceiverType == this.receiver.resolvedType) {
+ return this.binding;
+ }
+ } else {
+ return this.binding;
+ }
+ }
+ return super.variableBinding();
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
index 3382ebb..55450db 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
@@ -31,16 +31,16 @@ public InstanceOfExpression(Expression expression, TypeReference type) {
}
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
- LocalVariableBinding local = this.expression.localVariableBinding();
- if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
+ VariableBinding variable = this.expression.variableBinding();
+ if (variable != null && (variable.type.tagBits & TagBits.IsBaseType) == 0) {
flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo).
unconditionalInits();
FlowInfo initsWhenTrue = flowInfo.copy();
- initsWhenTrue.markAsComparedEqualToNonNull(local);
+ initsWhenTrue.markAsComparedEqualToNonNull(variable );
if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
- initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
+ initsWhenTrue.markedAsNullOrNonNullInAssertExpression(variable);
}
- flowContext.recordUsingNullReference(currentScope, local,
+ flowContext.recordUsingNullReference(currentScope, variable,
this.expression, FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF, flowInfo);
// no impact upon enclosing try context
return FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index 46d4540..c97fab2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -115,6 +115,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
// NullReferenceTest#test0510
}
manageSyntheticAccessIfNecessary(currentScope, flowInfo);
+ // a method call can result in changed values for fields,
+ // so wipe out null info for fields collected till now.
+ flowInfo.resetNullInfoForFields();
return flowInfo;
}
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
index d625d5b..5fda9bf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
@@ -806,6 +806,15 @@ public LocalVariableBinding localVariableBinding() {
return null;
}
+public VariableBinding variableBinding() {
+ switch (this.bits & ASTNode.RestrictiveFlagMASK) {
+ case Binding.FIELD :
+ // reading a field
+ case Binding.LOCAL : // reading a local variable
+ return (VariableBinding) this.binding;
+ }
+ return null;
+}
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
//If inlinable field, forget the access emulation, the code gen will directly target it
if (((this.bits & ASTNode.DepthMASK) == 0) || (this.constant != Constant.NotAConstant)) {
@@ -858,11 +867,10 @@ public int nullStatus(FlowInfo flowInfo) {
}
switch (this.bits & ASTNode.RestrictiveFlagMASK) {
case Binding.FIELD : // reading a field
- return FlowInfo.UNKNOWN;
case Binding.LOCAL : // reading a local variable
- LocalVariableBinding local = (LocalVariableBinding) this.binding;
- if (local != null)
- return flowInfo.nullStatus(local);
+ VariableBinding variable = (VariableBinding) this.binding;
+ if (variable != null)
+ return flowInfo.nullStatus(variable);
}
return FlowInfo.NON_NULL; // never get there
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index 8f68b7c..66c17f5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -59,7 +59,6 @@ public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowCo
public static final int COMPLAINED_FAKE_REACHABLE = 1;
public static final int COMPLAINED_UNREACHABLE = 2;
-
/** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */
protected void analyseArguments(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, MethodBinding methodBinding, Expression[] arguments)
{
@@ -98,12 +97,12 @@ protected void analyseArguments(BlockScope currentScope, FlowContext flowContext
/** Check null-ness of 'local' against a possible null annotation */
protected int checkAssignmentAgainstNullAnnotation(BlockScope currentScope, FlowContext flowContext,
- LocalVariableBinding local, int nullStatus, Expression expression)
+ VariableBinding var, int nullStatus, Expression expression)
{
- if (local != null
- && (local.tagBits & TagBits.AnnotationNonNull) != 0
+ if (var != null
+ && (var.tagBits & TagBits.AnnotationNonNull) != 0
&& nullStatus != FlowInfo.NON_NULL) {
- flowContext.recordNullityMismatch(currentScope, expression, nullStatus, local.type);
+ flowContext.recordNullityMismatch(currentScope, expression, nullStatus, var.type);
nullStatus=FlowInfo.NON_NULL;
}
return nullStatus;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
index f5d41ea..b6566bf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
@@ -651,7 +651,7 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
// branch, since the previous initializer already got the blame.
if (staticFieldInfo == FlowInfo.DEAD_END) {
this.staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
- staticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
+ staticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE);
}
} else {
if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
@@ -667,7 +667,7 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
// branch, since the previous initializer already got the blame.
if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
this.initializerScope.problemReporter().initializerMustCompleteNormally(field);
- nonStaticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
+ nonStaticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE);
}
}
}
@@ -683,6 +683,8 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
}
if (this.methods != null) {
UnconditionalFlowInfo outerInfo = flowInfo.unconditionalFieldLessCopy();
+ //int fieldOffset = isLocal ? this.scope.cumulativeFieldCount : this.maxFieldCount;
+ //int fieldStart = isLocal ? this.scope.localTypeFieldIdStart : 0;
FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
for (int i = 0, count = this.methods.length; i < count; i++) {
AbstractMethodDeclaration method = this.methods[i];
@@ -1038,8 +1040,6 @@ public void resolve() {
}
} while ((current = current.enclosingType()) != null);
}
- // this.maxFieldCount might already be set
- int localMaxFieldCount = 0;
int lastVisibleFieldID = -1;
boolean hasEnumConstants = false;
FieldDeclaration[] enumConstantsWithoutBody = null;
@@ -1049,11 +1049,22 @@ public void resolve() {
this.typeParameters[i].resolve(this.scope);
}
}
- if (this.memberTypes != null) {
- for (int i = 0, count = this.memberTypes.length; i < count; i++) {
- this.memberTypes[i].resolve(this.scope);
+ // field count from supertypes should be included in maxFieldCount,
+ // so that a field from supertype doesn't end up with same id as a local variable
+ // in a method being analyzed.
+ int superFieldsCount = 0;
+ ReferenceBinding superClassBinding = sourceType.superclass;
+ while (superClassBinding != null) {
+ FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields();
+ if (unResolvedFields != null) {
+ superFieldsCount += unResolvedFields.length;
}
+ superFieldsCount += findFieldCountFromSuperInterfaces(superClassBinding.superInterfaces());
+ superClassBinding = superClassBinding.superclass();
}
+ ReferenceBinding[] superInterfacesBinding = this.binding.superInterfaces;
+ superFieldsCount += findFieldCountFromSuperInterfaces(superInterfacesBinding);
+ this.scope.cumulativeFieldCount += superFieldsCount;
if (this.fields != null) {
for (int i = 0, count = this.fields.length; i < count; i++) {
FieldDeclaration field = this.fields[i];
@@ -1074,13 +1085,13 @@ public void resolve() {
this.ignoreFurtherInvestigation = true;
continue;
}
+ field.binding.id += superFieldsCount;
if (needSerialVersion
&& ((fieldBinding.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)) == (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal))
&& CharOperation.equals(TypeConstants.SERIALVERSIONUID, fieldBinding.name)
&& TypeBinding.LONG == fieldBinding.type) {
needSerialVersion = false;
}
- localMaxFieldCount++;
lastVisibleFieldID = field.binding.id;
break;
@@ -1090,9 +1101,15 @@ public void resolve() {
}
field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
}
- }
- if (this.maxFieldCount < localMaxFieldCount) {
- this.maxFieldCount = localMaxFieldCount;
+ }
+ // if (this.maxFieldCount < localMaxFieldCount) {
+ // this.maxFieldCount = localMaxFieldCount;
+ // }
+ this.maxFieldCount = this.scope.cumulativeFieldCount;
+ if (this.memberTypes != null) {
+ for (int i = 0, count = this.memberTypes.length; i < count; i++) {
+ this.memberTypes[i].resolve(this.scope);
+ }
}
if (needSerialVersion) {
//check that the current type doesn't extend javax.rmi.CORBA.Stub
@@ -1180,6 +1197,17 @@ public void resolve() {
}
}
+private int findFieldCountFromSuperInterfaces(ReferenceBinding[] superinterfaces) {
+ int numOfFields = 0;
+ if (superinterfaces == null)
+ return numOfFields ;
+ for (int i = 0; i < superinterfaces.length; i++) {
+ numOfFields += superinterfaces[i].fieldCount();
+ numOfFields += findFieldCountFromSuperInterfaces(superinterfaces[i].superInterfaces());
+ }
+ return numOfFields;
+}
+
/**
* Resolve a local type declaration
*/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
index 5cb4166..718f23a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
@@ -13,6 +13,7 @@ package org.eclipse.jdt.internal.compiler.flow;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
/**
* Record conditional initialization status during definite assignment analysis
@@ -85,17 +86,17 @@ public boolean isDefinitelyAssigned(LocalVariableBinding local) {
&& this.initsWhenFalse.isDefinitelyAssigned(local);
}
-public boolean isDefinitelyNonNull(LocalVariableBinding local) {
+public boolean isDefinitelyNonNull(VariableBinding local) {
return this.initsWhenTrue.isDefinitelyNonNull(local)
&& this.initsWhenFalse.isDefinitelyNonNull(local);
}
-public boolean isDefinitelyNull(LocalVariableBinding local) {
+public boolean isDefinitelyNull(VariableBinding local) {
return this.initsWhenTrue.isDefinitelyNull(local)
&& this.initsWhenFalse.isDefinitelyNull(local);
}
-public boolean isDefinitelyUnknown(LocalVariableBinding local) {
+public boolean isDefinitelyUnknown(VariableBinding local) {
return this.initsWhenTrue.isDefinitelyUnknown(local)
&& this.initsWhenFalse.isDefinitelyUnknown(local);
}
@@ -110,37 +111,37 @@ public boolean isPotentiallyAssigned(LocalVariableBinding local) {
|| this.initsWhenFalse.isPotentiallyAssigned(local);
}
-public boolean isPotentiallyNonNull(LocalVariableBinding local) {
+public boolean isPotentiallyNonNull(VariableBinding local) {
return this.initsWhenTrue.isPotentiallyNonNull(local)
|| this.initsWhenFalse.isPotentiallyNonNull(local);
}
-public boolean isPotentiallyNull(LocalVariableBinding local) {
+public boolean isPotentiallyNull(VariableBinding local) {
return this.initsWhenTrue.isPotentiallyNull(local)
|| this.initsWhenFalse.isPotentiallyNull(local);
}
-public boolean isPotentiallyUnknown(LocalVariableBinding local) {
+public boolean isPotentiallyUnknown(VariableBinding local) {
return this.initsWhenTrue.isPotentiallyUnknown(local)
|| this.initsWhenFalse.isPotentiallyUnknown(local);
}
-public boolean isProtectedNonNull(LocalVariableBinding local) {
+public boolean isProtectedNonNull(VariableBinding local) {
return this.initsWhenTrue.isProtectedNonNull(local)
&& this.initsWhenFalse.isProtectedNonNull(local);
}
-public boolean isProtectedNull(LocalVariableBinding local) {
+public boolean isProtectedNull(VariableBinding local) {
return this.initsWhenTrue.isProtectedNull(local)
&& this.initsWhenFalse.isProtectedNull(local);
}
-public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
+public void markAsComparedEqualToNonNull(VariableBinding local) {
this.initsWhenTrue.markAsComparedEqualToNonNull(local);
this.initsWhenFalse.markAsComparedEqualToNonNull(local);
}
-public void markAsComparedEqualToNull(LocalVariableBinding local) {
+public void markAsComparedEqualToNull(VariableBinding local) {
this.initsWhenTrue.markAsComparedEqualToNull(local);
this.initsWhenFalse.markAsComparedEqualToNull(local);
}
@@ -155,37 +156,42 @@ public void markAsDefinitelyAssigned(LocalVariableBinding local) {
this.initsWhenFalse.markAsDefinitelyAssigned(local);
}
-public void markAsDefinitelyNonNull(LocalVariableBinding local) {
+public void markAsDefinitelyNonNull(VariableBinding local) {
this.initsWhenTrue.markAsDefinitelyNonNull(local);
this.initsWhenFalse.markAsDefinitelyNonNull(local);
}
-public void markAsDefinitelyNull(LocalVariableBinding local) {
+public void markAsDefinitelyNull(VariableBinding local) {
this.initsWhenTrue.markAsDefinitelyNull(local);
this.initsWhenFalse.markAsDefinitelyNull(local);
}
-public void resetNullInfo(LocalVariableBinding local) {
+public void resetNullInfo(VariableBinding local) {
this.initsWhenTrue.resetNullInfo(local);
this.initsWhenFalse.resetNullInfo(local);
}
-public void markPotentiallyNullBit(LocalVariableBinding local) {
+public void resetNullInfoForFields() {
+ this.initsWhenTrue.resetNullInfoForFields();
+ this.initsWhenFalse.resetNullInfoForFields();
+}
+
+public void markPotentiallyNullBit(VariableBinding local) {
this.initsWhenTrue.markPotentiallyNullBit(local);
this.initsWhenFalse.markPotentiallyNullBit(local);
}
-public void markPotentiallyNonNullBit(LocalVariableBinding local) {
+public void markPotentiallyNonNullBit(VariableBinding local) {
this.initsWhenTrue.markPotentiallyNonNullBit(local);
this.initsWhenFalse.markPotentiallyNonNullBit(local);
}
-public void markAsDefinitelyUnknown(LocalVariableBinding local) {
+public void markAsDefinitelyUnknown(VariableBinding local) {
this.initsWhenTrue.markAsDefinitelyUnknown(local);
this.initsWhenFalse.markAsDefinitelyUnknown(local);
}
-public void markPotentiallyUnknownBit(LocalVariableBinding local) {
+public void markPotentiallyUnknownBit(VariableBinding local) {
this.initsWhenTrue.markPotentiallyUnknownBit(local);
this.initsWhenFalse.markPotentiallyUnknownBit(local);
}
@@ -243,12 +249,12 @@ public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
mergedWith(this.initsWhenFalse.unconditionalInits());
}
-public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
+public void markedAsNullOrNonNullInAssertExpression(VariableBinding local) {
this.initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
this.initsWhenFalse.markedAsNullOrNonNullInAssertExpression(local);
}
-public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
+public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding local) {
return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(local)
|| this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(local));
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
index d148222..d9234ef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
@@ -32,7 +32,7 @@ public class FinallyFlowContext extends FlowContext {
VariableBinding[] finalVariables;
int assignCount;
- LocalVariableBinding[] nullLocals;
+ VariableBinding[] nullVariables;
Expression[] nullReferences;
int[] nullCheckTypes;
int nullCount;
@@ -87,29 +87,28 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
for (int i = 0; i < this.nullCount; i++) {
if (this.nullCheckTypes[i] == ASSIGN_TO_NONNULL)
this.parent.recordNullityMismatch(scope, this.nullReferences[i],
- flowInfo.nullStatus(this.nullLocals[i]), this.expectedTypes[i]);
+ flowInfo.nullStatus(this.nullVariables[i]), this.expectedTypes[i]);
else
- this.parent.recordUsingNullReference(scope, this.nullLocals[i],
+ this.parent.recordUsingNullReference(scope, this.nullVariables[i],
this.nullReferences[i], this.nullCheckTypes[i], flowInfo);
-
}
}
else { // no enclosing loop, be as precise as possible right now
for (int i = 0; i < this.nullCount; i++) {
Expression expression = this.nullReferences[i];
// final local variable
- LocalVariableBinding local = this.nullLocals[i];
+ VariableBinding local = this.nullVariables[i];
switch (this.nullCheckTypes[i]) {
case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
if (flowInfo.isDefinitelyNonNull(local)) {
if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
+ scope.problemReporter().variableNonNullComparedToNull(local, expression);
}
}
continue;
@@ -123,27 +122,27 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNull(local, expression);
}
continue;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
+ scope.problemReporter().variableNullComparedToNonNull(local, expression);
}
continue;
case FlowContext.IN_ASSIGNMENT:
- scope.problemReporter().localVariableRedundantNullAssignment(local, expression);
+ scope.problemReporter().variableRedundantNullAssignment(local, expression);
continue;
case FlowContext.IN_INSTANCEOF:
- scope.problemReporter().localVariableNullInstanceof(local, expression);
+ scope.problemReporter().variableNullInstanceof(local, expression);
continue;
}
} else if (flowInfo.isPotentiallyNull(local)) {
@@ -151,14 +150,14 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
case FlowContext.IN_COMPARISON_NULL:
this.nullReferences[i] = null;
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
continue;
}
break;
case FlowContext.IN_COMPARISON_NON_NULL:
this.nullReferences[i] = null;
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
continue;
}
break;
@@ -167,11 +166,11 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
break;
case MAY_NULL:
if (flowInfo.isDefinitelyNull(local)) {
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if (flowInfo.isPotentiallyNull(local)) {
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
}
break;
case ASSIGN_TO_NONNULL:
@@ -226,7 +225,7 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
return true;
}
- public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
+ public void recordUsingNullReference(Scope scope, VariableBinding local,
Expression reference, int checkType, FlowInfo flowInfo) {
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0 && !flowInfo.isDefinitelyUnknown(local)) {
if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) { // within an enclosing loop, be conservative
@@ -240,14 +239,14 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
if (flowInfo.cannotBeNull(local)) {
if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
} else if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, reference);
+ scope.problemReporter().variableNonNullComparedToNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -259,11 +258,11 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -271,34 +270,34 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
return;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
+ scope.problemReporter().variableNullComparedToNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
return;
case FlowContext.IN_ASSIGNMENT:
- scope.problemReporter().localVariableRedundantNullAssignment(local, reference);
+ scope.problemReporter().variableRedundantNullAssignment(local, reference);
return;
case FlowContext.IN_INSTANCEOF:
- scope.problemReporter().localVariableNullInstanceof(local, reference);
+ scope.problemReporter().variableNullInstanceof(local, reference);
return;
}
} else if (flowInfo.isPotentiallyNull(local)) {
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
@@ -310,7 +309,7 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
return;
}
if (flowInfo.canOnlyBeNull(local)) {
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
break;
@@ -325,14 +324,14 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
if (flowInfo.isDefinitelyNonNull(local)) {
if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, reference);
+ scope.problemReporter().variableNonNullComparedToNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -349,11 +348,11 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -361,34 +360,34 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
return;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
+ scope.problemReporter().variableNullComparedToNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
return;
case FlowContext.IN_ASSIGNMENT:
- scope.problemReporter().localVariableRedundantNullAssignment(local, reference);
+ scope.problemReporter().variableRedundantNullAssignment(local, reference);
return;
case FlowContext.IN_INSTANCEOF:
- scope.problemReporter().localVariableNullInstanceof(local, reference);
+ scope.problemReporter().variableNullInstanceof(local, reference);
return;
}
} else if (flowInfo.isPotentiallyNull(local)) {
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
@@ -397,11 +396,11 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
break;
case MAY_NULL :
if (flowInfo.isDefinitelyNull(local)) {
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if (flowInfo.isPotentiallyNull(local)) {
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
if (flowInfo.isDefinitelyNonNull(local)) {
@@ -433,17 +432,17 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
}
}
-protected void recordNullReference(LocalVariableBinding local,
+protected void recordNullReference(VariableBinding local,
Expression expression, int status) {
if (this.nullCount == 0) {
- this.nullLocals = new LocalVariableBinding[5];
+ this.nullVariables = new VariableBinding[5];
this.nullReferences = new Expression[5];
this.nullCheckTypes = new int[5];
}
- else if (this.nullCount == this.nullLocals.length) {
+ else if (this.nullCount == this.nullVariables.length) {
int newLength = this.nullCount * 2;
- System.arraycopy(this.nullLocals, 0,
- this.nullLocals = new LocalVariableBinding[newLength], 0,
+ System.arraycopy(this.nullVariables, 0,
+ this.nullVariables = new VariableBinding[newLength], 0,
this.nullCount);
System.arraycopy(this.nullReferences, 0,
this.nullReferences = new Expression[newLength], 0,
@@ -452,7 +451,7 @@ protected void recordNullReference(LocalVariableBinding local,
this.nullCheckTypes = new int[newLength], 0,
this.nullCount);
}
- this.nullLocals[this.nullCount] = local;
+ this.nullVariables[this.nullCount] = local;
this.nullReferences[this.nullCount] = expression;
this.nullCheckTypes[this.nullCount++] = status;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
index 98caf30..33fd6c5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
@@ -588,7 +588,7 @@ protected boolean recordFinalAssignment(VariableBinding variable, Reference fina
* combined with a context indicator (one of {@link #IN_COMPARISON_NULL},
* {@link #IN_COMPARISON_NON_NULL}, {@link #IN_ASSIGNMENT} or {@link #IN_INSTANCEOF})
*/
-protected void recordNullReference(LocalVariableBinding local,
+protected void recordNullReference(VariableBinding local,
Expression expression, int status) {
// default implementation: do nothing
}
@@ -631,7 +631,7 @@ public void recordSettingFinal(VariableBinding variable, Reference finalReferenc
* be known at the time of calling this method (they are influenced by
* code that follows the current point)
*/
-public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
+public void recordUsingNullReference(Scope scope, VariableBinding local,
Expression reference, int checkType, FlowInfo flowInfo) {
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 ||
flowInfo.isDefinitelyUnknown(local)) {
@@ -643,14 +643,14 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
if (flowInfo.isDefinitelyNonNull(local)) {
if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, reference);
+ scope.problemReporter().variableNonNullComparedToNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -670,11 +670,11 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -682,34 +682,34 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
return;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
+ scope.problemReporter().variableNullComparedToNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
return;
case FlowContext.IN_ASSIGNMENT:
- scope.problemReporter().localVariableRedundantNullAssignment(local, reference);
+ scope.problemReporter().variableRedundantNullAssignment(local, reference);
return;
case FlowContext.IN_INSTANCEOF:
- scope.problemReporter().localVariableNullInstanceof(local, reference);
+ scope.problemReporter().variableNullInstanceof(local, reference);
return;
}
} else if (flowInfo.isPotentiallyNull(local)) {
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
@@ -720,11 +720,11 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
break;
case MAY_NULL :
if (flowInfo.isDefinitelyNull(local)) {
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if (flowInfo.isPotentiallyNull(local)) {
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
index b931372..cdab292 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
@@ -17,6 +17,7 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
public abstract class FlowInfo {
@@ -94,39 +95,42 @@ abstract public FlowInfo addPotentialInitializationsFrom(FlowInfo otherInits);
}
/**
- * Check whether a given local variable is known to be unable to gain a definite
+ * Check whether a given field or local variable is known to be unable to gain a definite
* non null or definite null status by the use of an enclosing flow info. The
* semantics are that if the current flow info marks the variable as potentially
* unknown or else as being both potentially null and potentially non null,
* then it won't ever be promoted as definitely null or definitely non null. (It
* could still get promoted to definite unknown).
- * @param local the variable to check
- * @return true iff this flow info prevents local from being promoted to
+ * @param binding the field or local variable to check
+ * @return true iff this flow info prevents field or local from being promoted to
* definite non null or definite null against an enclosing flow info
*/
-public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) {
- return isPotentiallyUnknown(local) ||
- isPotentiallyNonNull(local) && isPotentiallyNull(local);
+public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding binding) {
+ return isPotentiallyUnknown(binding) ||
+ isPotentiallyNonNull(binding) && isPotentiallyNull(binding);
}
/**
- * Check whether a given local variable is known to be non null, either because
+ * Check whether a given field or local variable is known to be non null, either because
* it is definitely non null, or because is has been tested against non null.
- * @param local the variable to ckeck
- * @return true iff local cannot be null for this flow info
+ * @param binding the field or local to check
+ * @return true iff field or local cannot be null for this flow info
*/
-public boolean cannotBeNull(LocalVariableBinding local) {
- return isDefinitelyNonNull(local) || isProtectedNonNull(local);
+public boolean cannotBeNull(VariableBinding binding) {
+ return isDefinitelyNonNull(binding) || isProtectedNonNull(binding);
}
/**
- * Check whether a given local variable is known to be null, either because it
- * is definitely null, or because is has been tested against null.
- * @param local the variable to ckeck
- * @return true iff local can only be null for this flow info
+ * Check whether a given field or local variable is known to be null, either because it
+ * is definitely null, or because is has been tested against null. Note that for fields,
+ * this method only takes compile time analysis into account and there's no
+ * guarantee of the field being definitely null during runtime
+ * since it can be modified in some other thread.
+ * @param binding the field or local to check
+ * @return true iff field or local can only be null for this flow info
*/
-public boolean canOnlyBeNull(LocalVariableBinding local) {
- return isDefinitelyNull(local) || isProtectedNull(local);
+public boolean canOnlyBeNull(VariableBinding binding) {
+ return isDefinitelyNull(binding) || isProtectedNull(binding);
}
/**
@@ -174,25 +178,29 @@ abstract public FlowInfo initsWhenFalse();
public abstract boolean isDefinitelyAssigned(LocalVariableBinding local);
/**
- * Check status of definite non-null value for a given local variable.
- * @param local the variable to ckeck
- * @return true iff local is definitely non null for this flow info
+ * Check status of definite non-null value for a given field or local variable. Note that for fields, this method only
+ * takes compile time analysis into account and there's no guarantee of the field being definitely non null during runtime
+ * since it can be modified in some other thread.
+ * @param binding the field or local to check
+ * @return true iff field or local is definitely non null for this flow info
*/
- public abstract boolean isDefinitelyNonNull(LocalVariableBinding local);
+ public abstract boolean isDefinitelyNonNull(VariableBinding binding);
/**
- * Check status of definite null value for a given local variable.
- * @param local the variable to ckeck
- * @return true iff local is definitely null for this flow info
+ * Check status of definite null value for a given field or local variable. Note that for fields, this method only
+ * takes compile time analysis into account and there's no guarantee of the field being definitely null during runtime
+ * since it can be modified in some other thread.
+ * @param binding the field or local to check
+ * @return true iff field or local is definitely null for this flow info
*/
-public abstract boolean isDefinitelyNull(LocalVariableBinding local);
+public abstract boolean isDefinitelyNull(VariableBinding binding);
/**
- * Check status of definite unknown value for a given local variable.
- * @param local the variable to ckeck
- * @return true iff local is definitely unknown for this flow info
+ * Check status of definite unknown value for a given field or local variable.
+ * @param binding the field or local to check
+ * @return true iff field or local is definitely unknown for this flow info
*/
-public abstract boolean isDefinitelyUnknown(LocalVariableBinding local);
+public abstract boolean isDefinitelyUnknown(VariableBinding binding);
/**
* Check status of potential assignment for a field.
@@ -206,59 +214,59 @@ public abstract boolean isDefinitelyUnknown(LocalVariableBinding local);
abstract public boolean isPotentiallyAssigned(LocalVariableBinding field);
/**
- * Check status of potential null assignment for a local. Return true if there
+ * Check status of potential null assignment for a field or local. Return true if there
* is a reasonable expectation that the variable be non null at this point.
- * @param local LocalVariableBinding - the binding for the checked local
- * @return true if there is a reasonable expectation that local be non null at
+ * @param binding VariableBinding - the binding for the checked field or local
+ * @return true if there is a reasonable expectation that the field or local be non null at
* this point
*/
-public abstract boolean isPotentiallyNonNull(LocalVariableBinding local);
+public abstract boolean isPotentiallyNonNull(VariableBinding binding);
/**
- * Check status of potential null assignment for a local. Return true if there
+ * Check status of potential null assignment for a field or local. Return true if there
* is a reasonable expectation that the variable be null at this point. This
* includes the protected null case, so as to augment diagnostics, but does not
* really check that someone deliberately assigned to null on any specific
* path
- * @param local LocalVariableBinding - the binding for the checked local
- * @return true if there is a reasonable expectation that local be null at
+ * @param binding VariableBinding - the binding for the checked field or local
+ * @return true if there is a reasonable expectation that the field or local be null at
* this point
*/
-public abstract boolean isPotentiallyNull(LocalVariableBinding local);
+public abstract boolean isPotentiallyNull(VariableBinding binding);
/**
- * Return true if the given local may have been assigned to an unknown value.
- * @param local the local to check
- * @return true if the given local may have been assigned to an unknown value
+ * Return true if the given field or local may have been assigned to an unknown value.
+ * @param binding the field or local to check
+ * @return true if the given field or local may have been assigned to an unknown value
*/
-public abstract boolean isPotentiallyUnknown(LocalVariableBinding local);
+public abstract boolean isPotentiallyUnknown(VariableBinding binding);
/**
- * Return true if the given local is protected by a test against a non null
+ * Return true if the given field or local is protected by a test against a non null
* value.
- * @param local the local to check
- * @return true if the given local is protected by a test against a non null
+ * @param binding the field or local to check
+ * @return true if the given field or local is protected by a test against a non null
*/
-public abstract boolean isProtectedNonNull(LocalVariableBinding local);
+public abstract boolean isProtectedNonNull(VariableBinding binding);
/**
- * Return true if the given local is protected by a test against null.
- * @param local the local to check
- * @return true if the given local is protected by a test against null
+ * Return true if the given field or local is protected by a test against null.
+ * @param binding the field or local to check
+ * @return true if the given field or local is protected by a test against null
*/
-public abstract boolean isProtectedNull(LocalVariableBinding local);
+public abstract boolean isProtectedNull(VariableBinding binding);
/**
- * Record that a local variable got checked to be non null.
- * @param local the checked local variable
+ * Record that a field or local variable got checked to be non null.
+ * @param binding the checked field or local variable
*/
-abstract public void markAsComparedEqualToNonNull(LocalVariableBinding local);
+abstract public void markAsComparedEqualToNonNull(VariableBinding binding);
/**
- * Record that a local variable got checked to be null.
- * @param local the checked local variable
+ * Record that a field or local variable got checked to be null.
+ * @param binding the checked field or local variable
*/
-abstract public void markAsComparedEqualToNull(LocalVariableBinding local);
+abstract public void markAsComparedEqualToNull(VariableBinding binding);
/**
* Record a field got definitely assigned.
@@ -266,34 +274,38 @@ abstract public void markAsComparedEqualToNull(LocalVariableBinding local);
abstract public void markAsDefinitelyAssigned(FieldBinding field);
/**
- * Record a local got definitely assigned to a non-null value.
+ * Record a field or local got definitely assigned to a non-null value.
*/
- abstract public void markAsDefinitelyNonNull(LocalVariableBinding local);
+ abstract public void markAsDefinitelyNonNull(VariableBinding binding);
/**
- * Record a local got definitely assigned to null.
+ * Record a field or local got definitely assigned to null.
*/
- abstract public void markAsDefinitelyNull(LocalVariableBinding local);
+ abstract public void markAsDefinitelyNull(VariableBinding binding);
/**
- * Reset all null-information about a given local.
+ * Reset all null-information about a given field or local.
*/
- abstract public void resetNullInfo(LocalVariableBinding local);
+ abstract public void resetNullInfo(VariableBinding binding);
/**
- * Record a local may have got assigned to unknown (set the bit on existing info).
+ * variant of {@link #resetNullInfo(VariableBinding)} for resetting null info for all fields
*/
- abstract public void markPotentiallyUnknownBit(LocalVariableBinding local);
+ abstract public void resetNullInfoForFields();
+ /**
+ * Record a field or local may have got assigned to unknown (set the bit on existing info).
+ */
+ abstract public void markPotentiallyUnknownBit(VariableBinding binding);
/**
- * Record a local may have got assigned to null (set the bit on existing info).
+ * Record a field or local may have got assigned to null (set the bit on existing info).
*/
- abstract public void markPotentiallyNullBit(LocalVariableBinding local);
+ abstract public void markPotentiallyNullBit(VariableBinding binding);
/**
- * Record a local may have got assigned to non-null (set the bit on existing info).
+ * Record a field or local may have got assigned to non-null (set the bit on existing info).
*/
- abstract public void markPotentiallyNonNullBit(LocalVariableBinding local);
+ abstract public void markPotentiallyNonNullBit(VariableBinding binding);
/**
* Record a local got definitely assigned.
@@ -301,59 +313,59 @@ abstract public void markAsComparedEqualToNull(LocalVariableBinding local);
abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
/**
- * Record a local got definitely assigned to an unknown value.
+ * Record a field or local got definitely assigned to an unknown value.
*/
-abstract public void markAsDefinitelyUnknown(LocalVariableBinding local);
+abstract public void markAsDefinitelyUnknown(VariableBinding binding);
/**
- * Mark the null status of the given local according to the given status
- * @param local
+ * Mark the null status of the given field or local according to the given status
+ * @param binding
* @param nullStatus bitset of FLowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
*/
-public void markNullStatus(LocalVariableBinding local, int nullStatus) {
+public void markNullStatus(VariableBinding binding, int nullStatus) {
switch(nullStatus) {
// definite status?
case FlowInfo.UNKNOWN :
- markAsDefinitelyUnknown(local);
+ markAsDefinitelyUnknown(binding);
break;
case FlowInfo.NULL :
- markAsDefinitelyNull(local);
+ markAsDefinitelyNull(binding);
break;
case FlowInfo.NON_NULL :
- markAsDefinitelyNonNull(local);
+ markAsDefinitelyNonNull(binding);
break;
default:
// collect potential status:
- resetNullInfo(local);
+ resetNullInfo(binding);
if ((nullStatus & FlowInfo.POTENTIALLY_UNKNOWN) != 0)
- markPotentiallyUnknownBit(local);
+ markPotentiallyUnknownBit(binding);
if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0)
- markPotentiallyNullBit(local);
+ markPotentiallyNullBit(binding);
if ((nullStatus & FlowInfo.POTENTIALLY_NON_NULL) != 0)
- markPotentiallyNonNullBit(local);
+ markPotentiallyNonNullBit(binding);
if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL|FlowInfo.POTENTIALLY_UNKNOWN)) == 0)
- markAsDefinitelyUnknown(local);
+ markAsDefinitelyUnknown(binding);
}
}
/**
- * Answer the null status of the given local
- * @param local
+ * Answer the null status of the given field or local
+ * @param binding
* @return bitset of FlowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
*/
-public int nullStatus(LocalVariableBinding local) {
- if (isDefinitelyUnknown(local))
+public int nullStatus(VariableBinding binding) {
+ if (isDefinitelyUnknown(binding))
return FlowInfo.UNKNOWN;
- if (isDefinitelyNull(local))
+ if (isDefinitelyNull(binding))
return FlowInfo.NULL;
- if (isDefinitelyNonNull(local))
+ if (isDefinitelyNonNull(binding))
return FlowInfo.NON_NULL;
int status = 0;
- if (isPotentiallyUnknown(local))
+ if (isPotentiallyUnknown(binding))
status |= FlowInfo.POTENTIALLY_UNKNOWN;
- if (isPotentiallyNull(local))
+ if (isPotentiallyNull(binding))
status |= FlowInfo.POTENTIALLY_NULL;
- if (isPotentiallyNonNull(local))
+ if (isPotentiallyNonNull(binding))
status |= FlowInfo.POTENTIALLY_NON_NULL;
if (status > 0)
return status;
@@ -601,14 +613,14 @@ abstract public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect();
* where this variable is being checked against null
*/
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
-abstract public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local);
+abstract public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding);
/**
* Returns true if the local variable being checked for was marked as null or not null
* inside an assert expression due to comparison against null.
*/
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
-abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local);
+abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding);
/**
* Resets the definite and potential initialization info for the given local variable
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
index 38295c8..6013dd0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
@@ -47,7 +47,7 @@ public class LoopingFlowContext extends SwitchFlowContext {
VariableBinding finalVariables[];
int assignCount = 0;
- LocalVariableBinding[] nullLocals;
+ VariableBinding[] nullVariables;
Expression[] nullReferences;
int[] nullCheckTypes;
int nullCount;
@@ -143,7 +143,7 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) {
// check only immutable null checks on innermost looping context
for (int i = 0; i < this.nullCount; i++) {
- LocalVariableBinding local = this.nullLocals[i];
+ VariableBinding local = this.nullVariables[i];
Expression expression = this.nullReferences[i];
// final local variable
switch (this.nullCheckTypes[i]) {
@@ -153,11 +153,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
this.nullReferences[i] = null;
if (this.nullCheckTypes[i] == (CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
+ scope.problemReporter().variableNonNullComparedToNull(local, expression);
}
}
continue;
@@ -169,11 +169,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
this.nullReferences[i] = null;
if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
+ scope.problemReporter().variableNonNullComparedToNull(local, expression);
}
}
continue;
@@ -182,11 +182,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
this.nullReferences[i] = null;
if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNull(local, expression);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
+ scope.problemReporter().variableNullComparedToNonNull(local, expression);
}
}
continue;
@@ -201,27 +201,27 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNull(local, expression);
}
continue;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
+ scope.problemReporter().variableNullComparedToNonNull(local, expression);
}
continue;
case FlowContext.IN_ASSIGNMENT:
- scope.problemReporter().localVariableRedundantNullAssignment(local, expression);
+ scope.problemReporter().variableRedundantNullAssignment(local, expression);
continue;
case FlowContext.IN_INSTANCEOF:
- scope.problemReporter().localVariableNullInstanceof(local, expression);
+ scope.problemReporter().variableNullInstanceof(local, expression);
continue;
}
} else if (flowInfo.isPotentiallyNull(local)) {
@@ -229,14 +229,14 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
case FlowContext.IN_COMPARISON_NULL:
this.nullReferences[i] = null;
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
continue;
}
break;
case FlowContext.IN_COMPARISON_NON_NULL:
this.nullReferences[i] = null;
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
continue;
}
break;
@@ -246,7 +246,7 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
case MAY_NULL:
if (flowInfo.isDefinitelyNull(local)) {
this.nullReferences[i] = null;
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
break;
@@ -265,7 +265,7 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
for (int i = 0; i < this.nullCount; i++) {
Expression expression = this.nullReferences[i];
// final local variable
- LocalVariableBinding local = this.nullLocals[i];
+ VariableBinding local = this.nullVariables[i];
switch (this.nullCheckTypes[i]) {
case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
@@ -273,11 +273,11 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
this.nullReferences[i] = null;
if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
+ scope.problemReporter().variableNonNullComparedToNull(local, expression);
}
}
continue;
@@ -292,27 +292,27 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
+ scope.problemReporter().variableRedundantCheckOnNull(local, expression);
}
continue;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
+ scope.problemReporter().variableNullComparedToNonNull(local, expression);
}
continue;
case FlowContext.IN_ASSIGNMENT:
- scope.problemReporter().localVariableRedundantNullAssignment(local, expression);
+ scope.problemReporter().variableRedundantNullAssignment(local, expression);
continue;
case FlowContext.IN_INSTANCEOF:
- scope.problemReporter().localVariableNullInstanceof(local, expression);
+ scope.problemReporter().variableNullInstanceof(local, expression);
continue;
}
} else if (flowInfo.isPotentiallyNull(local)) {
@@ -320,14 +320,14 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
case FlowContext.IN_COMPARISON_NULL:
this.nullReferences[i] = null;
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
continue;
}
break;
case FlowContext.IN_COMPARISON_NON_NULL:
this.nullReferences[i] = null;
if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
continue;
}
break;
@@ -337,12 +337,12 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn
case MAY_NULL:
if (flowInfo.isDefinitelyNull(local)) {
this.nullReferences[i] = null;
- scope.problemReporter().localVariableNullReference(local, expression);
+ scope.problemReporter().variableNullReference(local, expression);
continue;
}
if (flowInfo.isPotentiallyNull(local)) {
this.nullReferences[i] = null;
- scope.problemReporter().localVariablePotentialNullReference(local, expression);
+ scope.problemReporter().variablePotentialNullReference(local, expression);
continue;
}
break;
@@ -474,27 +474,27 @@ public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo)
return true;
}
-protected void recordNullReference(LocalVariableBinding local,
+protected void recordNullReference(VariableBinding local,
Expression expression, int status) {
if (this.nullCount == 0) {
- this.nullLocals = new LocalVariableBinding[5];
+ this.nullVariables = new VariableBinding[5];
this.nullReferences = new Expression[5];
this.nullCheckTypes = new int[5];
}
- else if (this.nullCount == this.nullLocals.length) {
- System.arraycopy(this.nullLocals, 0,
- this.nullLocals = new LocalVariableBinding[this.nullCount * 2], 0, this.nullCount);
+ else if (this.nullCount == this.nullVariables.length) {
+ System.arraycopy(this.nullVariables, 0,
+ this.nullVariables = new VariableBinding[this.nullCount * 2], 0, this.nullCount);
System.arraycopy(this.nullReferences, 0,
this.nullReferences = new Expression[this.nullCount * 2], 0, this.nullCount);
System.arraycopy(this.nullCheckTypes, 0,
this.nullCheckTypes = new int[this.nullCount * 2], 0, this.nullCount);
}
- this.nullLocals[this.nullCount] = local;
+ this.nullVariables[this.nullCount] = local;
this.nullReferences[this.nullCount] = expression;
this.nullCheckTypes[this.nullCount++] = status;
}
-public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
+public void recordUsingNullReference(Scope scope, VariableBinding local,
Expression reference, int checkType, FlowInfo flowInfo) {
if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 ||
flowInfo.isDefinitelyUnknown(local)) {
@@ -506,14 +506,14 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
if (flowInfo.isDefinitelyNonNull(local)) {
if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNonNullComparedToNull(local, reference);
+ scope.problemReporter().variableNonNullComparedToNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -522,14 +522,14 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
} else if (flowInfo.isDefinitelyNull(local)) {
if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
} else {
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
+ scope.problemReporter().variableNullComparedToNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -573,11 +573,11 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
+ scope.problemReporter().variableRedundantCheckOnNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
@@ -585,34 +585,34 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
return;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
- scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
+ scope.problemReporter().variableNullComparedToNonNull(local, reference);
}
if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
}
return;
case FlowContext.IN_ASSIGNMENT:
- scope.problemReporter().localVariableRedundantNullAssignment(local, reference);
+ scope.problemReporter().variableRedundantNullAssignment(local, reference);
return;
case FlowContext.IN_INSTANCEOF:
- scope.problemReporter().localVariableNullInstanceof(local, reference);
+ scope.problemReporter().variableNullInstanceof(local, reference);
return;
}
} else if (flowInfo.isPotentiallyNull(local)) {
switch(checkType & CONTEXT_MASK) {
case FlowContext.IN_COMPARISON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
case FlowContext.IN_COMPARISON_NON_NULL:
if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
break;
@@ -631,11 +631,11 @@ public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
return;
}
if (flowInfo.isDefinitelyNull(local)) {
- scope.problemReporter().localVariableNullReference(local, reference);
+ scope.problemReporter().variableNullReference(local, reference);
return;
}
if (flowInfo.isPotentiallyNull(local)) {
- scope.problemReporter().localVariablePotentialNullReference(local, reference);
+ scope.problemReporter().variablePotentialNullReference(local, reference);
return;
}
recordNullReference(local, reference, checkType);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java
index 1470795..296b7e3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java
@@ -11,7 +11,8 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.flow;
-import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
/**
* A degenerate form of UnconditionalFlowInfo explicitly meant to capture
@@ -116,13 +117,18 @@ public NullInfoRegistry add(NullInfoRegistry other) {
return this;
}
-public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
+public void markAsComparedEqualToNonNull(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
+ if (position < BitCacheSize) { // use bits
// set protected non null
this.nullBit1 |= (1L << position);
if (COVERAGE_TEST_FLAG) {
@@ -161,13 +167,18 @@ public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
}
}
-public void markAsDefinitelyNonNull(LocalVariableBinding local) {
+public void markAsDefinitelyNonNull(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) { // use bits
// set assigned non null
this.nullBit3 |= (1L << position);
if (COVERAGE_TEST_FLAG) {
@@ -207,13 +218,18 @@ public void markAsDefinitelyNonNull(LocalVariableBinding local) {
}
// PREMATURE consider ignoring extra 0 to 2 included - means a1 should not be used either
// PREMATURE project protected non null onto something else
-public void markAsDefinitelyNull(LocalVariableBinding local) {
+public void markAsDefinitelyNull(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
+ if (position < BitCacheSize) { // use bits
// set assigned null
this.nullBit2 |= (1L << position);
if (COVERAGE_TEST_FLAG) {
@@ -252,13 +268,18 @@ public void markAsDefinitelyNull(LocalVariableBinding local) {
}
}
-public void markAsDefinitelyUnknown(LocalVariableBinding local) {
+public void markAsDefinitelyUnknown(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
+ if (position < BitCacheSize) { // use bits
// set assigned unknown
this.nullBit4 |= (1L << position);
if (COVERAGE_TEST_FLAG) {
@@ -407,13 +428,18 @@ public String toString(){
* Mark a local as potentially having been assigned to an unknown value.
* @param local the local to mark
*/
-public void markPotentiallyUnknownBit(LocalVariableBinding local) {
+public void markPotentiallyUnknownBit(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
mask = 1L << position;
isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$
@@ -454,12 +480,17 @@ public void markPotentiallyUnknownBit(LocalVariableBinding local) {
}
}
-public void markPotentiallyNullBit(LocalVariableBinding local) {
+public void markPotentiallyNullBit(VariableBinding local) {
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
mask = 1L << position;
isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$
@@ -500,12 +531,17 @@ public void markPotentiallyNullBit(LocalVariableBinding local) {
}
}
-public void markPotentiallyNonNullBit(LocalVariableBinding local) {
+public void markPotentiallyNonNullBit(VariableBinding local) {
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
mask = 1L << position;
isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
index ed1ae7a..74eecbf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
@@ -23,6 +23,7 @@ import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
/**
* Record initialization status during definite assignment analysis
@@ -520,13 +521,18 @@ public UnconditionalFlowInfo addPotentialNullInfoFrom(
return this;
}
-final public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) {
+final public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding local) {
if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
int position;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
return (
(~this.nullBit1
@@ -551,13 +557,18 @@ final public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local)
& (1L << (position % BitCacheSize))) != 0;
}
-final public boolean cannotBeNull(LocalVariableBinding local) {
+final public boolean cannotBeNull(VariableBinding local) {
if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
int position;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
return (this.nullBit1 & this.nullBit3
& ((this.nullBit2 & this.nullBit4) | ~this.nullBit2)
@@ -578,13 +589,18 @@ final public boolean cannotBeNull(LocalVariableBinding local) {
& (1L << (position % BitCacheSize))) != 0;
}
-final public boolean canOnlyBeNull(LocalVariableBinding local) {
+final public boolean canOnlyBeNull(VariableBinding local) {
if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
int position;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
return (this.nullBit1 & this.nullBit2
& (~this.nullBit3 | ~this.nullBit4)
@@ -750,7 +766,13 @@ final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
return isDefinitelyAssigned(local.id + this.maxFieldCount);
}
-final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
+final public boolean isDefinitelyNonNull(VariableBinding local) {
+ if (local instanceof FieldBinding && (this.tagBits & NULL_FLAG_MASK) == 0) {
+ // no local yet in scope. Came here because of a field being queried for non null
+ // will only happen for final fields, since they are assigned in a constructor or static block
+ // and we may currently be in some other method
+ this.tagBits |= NULL_FLAG_MASK;
+ }
// do not want to complain in unreachable code
if ((this.tagBits & UNREACHABLE) != 0 ||
(this.tagBits & NULL_FLAG_MASK) == 0) {
@@ -760,7 +782,16 @@ final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
local.constant() != Constant.NotAConstant) { // String instances
return true;
}
- int position = local.id + this.maxFieldCount;
+ int position;
+ if (local instanceof FieldBinding) {
+ if (local.isFinal() && ((FieldBinding)local).isStatic()) {
+ // static final field's null status may not be in the flow info
+ return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NON_NULL);
+ }
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
if (position < BitCacheSize) { // use bits
return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
& (1L << position)) != 0;
@@ -779,14 +810,29 @@ final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
& (1L << (position % BitCacheSize))) != 0;
}
-final public boolean isDefinitelyNull(LocalVariableBinding local) {
+final public boolean isDefinitelyNull(VariableBinding local) {
+ if (local instanceof FieldBinding && (this.tagBits & NULL_FLAG_MASK) == 0) {
+ // no local yet in scope. Came here because of a field being queried for non null
+ // will only happen for final fields, since they are assigned in a constructor or static block
+ // and we may currently be in some other method
+ this.tagBits |= NULL_FLAG_MASK;
+ }
// do not want to complain in unreachable code
if ((this.tagBits & UNREACHABLE) != 0 ||
(this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
- int position = local.id + this.maxFieldCount;
+ int position;
+ if (local instanceof FieldBinding) {
+ if (local.isFinal() && ((FieldBinding)local).isStatic()) {
+ // static final field's null status may not be in the flow info
+ return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NULL);
+ }
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
if (position < BitCacheSize) { // use bits
return ((this.nullBit1 & this.nullBit2
& (~this.nullBit3 | ~this.nullBit4))
@@ -806,13 +852,18 @@ final public boolean isDefinitelyNull(LocalVariableBinding local) {
& (1L << (position % BitCacheSize))) != 0;
}
-final public boolean isDefinitelyUnknown(LocalVariableBinding local) {
+final public boolean isDefinitelyUnknown(VariableBinding local) {
// do not want to complain in unreachable code
if ((this.tagBits & UNREACHABLE) != 0 ||
(this.tagBits & NULL_FLAG_MASK) == 0) {
return false;
}
- int position = local.id + this.maxFieldCount;
+ int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
if (position < BitCacheSize) { // use bits
return ((this.nullBit1 & this.nullBit4
& ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
@@ -866,13 +917,18 @@ final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
}
// TODO (Ayush) Check why this method does not return true for protected non null (1111)
-final public boolean isPotentiallyNonNull(LocalVariableBinding local) {
+final public boolean isPotentiallyNonNull(VariableBinding local) {
if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
int position;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) { // use bits
// use bits
return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
& (1L << position)) != 0;
@@ -892,13 +948,22 @@ final public boolean isPotentiallyNonNull(LocalVariableBinding local) {
}
// TODO (Ayush) Check why this method does not return true for protected null
-final public boolean isPotentiallyNull(LocalVariableBinding local) {
+final public boolean isPotentiallyNull(VariableBinding local) {
if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
int position;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ if (local.isFinal() && ((FieldBinding)local).isStatic()) {
+ // static final field's null status may not be in the flow info
+ return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.POTENTIALLY_NULL);
+ }
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
& (1L << position)) != 0;
@@ -917,13 +982,18 @@ final public boolean isPotentiallyNull(LocalVariableBinding local) {
& (1L << (position % BitCacheSize))) != 0;
}
-final public boolean isPotentiallyUnknown(LocalVariableBinding local) {
+final public boolean isPotentiallyUnknown(VariableBinding local) {
// do not want to complain in unreachable code
if ((this.tagBits & UNREACHABLE) != 0 ||
(this.tagBits & NULL_FLAG_MASK) == 0) {
return false;
}
- int position = local.id + this.maxFieldCount;
+ int position;
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
if (position < BitCacheSize) { // use bits
return (this.nullBit4
& (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
@@ -944,14 +1014,18 @@ final public boolean isPotentiallyUnknown(LocalVariableBinding local) {
& (1L << (position % BitCacheSize))) != 0;
}
-final public boolean isProtectedNonNull(LocalVariableBinding local) {
+final public boolean isProtectedNonNull(VariableBinding local) {
if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
int position;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
- // use bits
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) { // use bits
return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
}
// use extra vector
@@ -969,13 +1043,18 @@ final public boolean isProtectedNonNull(LocalVariableBinding local) {
& (1L << (position % BitCacheSize))) != 0;
}
-final public boolean isProtectedNull(LocalVariableBinding local) {
+final public boolean isProtectedNull(VariableBinding local) {
if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
(local.type.tagBits & TagBits.IsBaseType) != 0) {
return false;
}
int position;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
return (this.nullBit1 & this.nullBit2
& (this.nullBit3 ^ this.nullBit4)
@@ -1008,15 +1087,21 @@ protected static boolean isTrue(boolean expression, String message) {
throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$
return expression;
}
-public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
+public void markAsComparedEqualToNonNull(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
+ if (local instanceof FieldBinding) {
+ this.markNullStatus(local, FlowInfo.POTENTIALLY_NON_NULL);
+ return;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
long mask;
long a1, a2, a3, a4, na2;
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (position < BitCacheSize) {
// use bits
if (((mask = 1L << position)
& (a1 = this.nullBit1)
@@ -1105,14 +1190,20 @@ public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
}
}
-public void markAsComparedEqualToNull(LocalVariableBinding local) {
+public void markAsComparedEqualToNull(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
+ return;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
if (((mask = 1L << position) & this.nullBit1) != 0) {
if ((mask
@@ -1243,14 +1334,20 @@ public void markAsDefinitelyAssigned(LocalVariableBinding local) {
markAsDefinitelyAssigned(local.id + this.maxFieldCount);
}
-public void markAsDefinitelyNonNull(LocalVariableBinding local) {
+public void markAsDefinitelyNonNull(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
long mask;
int position;
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
+ if (local instanceof FieldBinding) {
+ this.markNullStatus(local, FlowInfo.POTENTIALLY_NON_NULL);
+ return;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) { // use bits
// set assigned non null
this.nullBit1 |= (mask = 1L << position);
this.nullBit3 |= mask;
@@ -1297,14 +1394,20 @@ public void markAsDefinitelyNonNull(LocalVariableBinding local) {
}
}
-public void markAsDefinitelyNull(LocalVariableBinding local) {
+public void markAsDefinitelyNull(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
long mask;
int position;
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
+ if (local instanceof FieldBinding) {
+ this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
+ return;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) { // use bits
// mark assigned null
this.nullBit1 |= (mask = 1L << position);
this.nullBit2 |= mask;
@@ -1357,14 +1460,19 @@ public void markAsDefinitelyNull(LocalVariableBinding local) {
*/
// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
// obvious
-public void markAsDefinitelyUnknown(LocalVariableBinding local) {
+public void markAsDefinitelyUnknown(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
long mask;
int position;
// position is zero-based
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
// mark assigned null
this.nullBit1 |= (mask = 1L << position);
@@ -1412,12 +1520,17 @@ public void markAsDefinitelyUnknown(LocalVariableBinding local) {
}
}
-public void resetNullInfo(LocalVariableBinding local) {
+public void resetNullInfo(VariableBinding local) {
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
this.nullBit1 &= (mask = ~(1L << position));
this.nullBit2 &= mask;
@@ -1440,17 +1553,54 @@ public void resetNullInfo(LocalVariableBinding local) {
}
}
+public void resetNullInfoForFields() {
+ if (this != DEAD_END) {
+ long mask;
+ if (this.maxFieldCount < BitCacheSize) {
+ // use bits
+ this.nullBit1 &= (mask = -1L << this.maxFieldCount);
+ this.nullBit2 &= mask;
+ this.nullBit3 &= mask;
+ this.nullBit4 &= mask;
+ }
+ else {
+ this.nullBit1 &= (mask = 0L);
+ this.nullBit2 &= mask;
+ this.nullBit3 &= mask;
+ this.nullBit4 &= mask;
+ if (this.extra != null){
+ for (int position = BitCacheSize; position < this.maxFieldCount; position++) {
+ // use extra vector
+ int vectorIndex = (position / BitCacheSize) - 1;
+ if (vectorIndex >= this.extra[2].length)
+ break; // No null info about fields beyond this point in the extra vector
+ this.extra[2][vectorIndex]
+ &= (mask = ~(1L << (position % BitCacheSize)));
+ this.extra[3][vectorIndex] &= mask;
+ this.extra[4][vectorIndex] &= mask;
+ this.extra[5][vectorIndex] &= mask;
+ }
+ }
+ }
+ }
+}
+
/**
* Mark a local as potentially having been assigned to an unknown value.
* @param local the local to mark
*/
-public void markPotentiallyUnknownBit(LocalVariableBinding local) {
+public void markPotentiallyUnknownBit(VariableBinding local) {
// protected from non-object locals in calling methods
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
mask = 1L << position;
isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$
@@ -1492,12 +1642,17 @@ public void markPotentiallyUnknownBit(LocalVariableBinding local) {
}
}
-public void markPotentiallyNullBit(LocalVariableBinding local) {
+public void markPotentiallyNullBit(VariableBinding local) {
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
mask = 1L << position;
isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$
@@ -1539,12 +1694,17 @@ public void markPotentiallyNullBit(LocalVariableBinding local) {
}
}
-public void markPotentiallyNonNullBit(LocalVariableBinding local) {
+public void markPotentiallyNonNullBit(VariableBinding local) {
if (this != DEAD_END) {
this.tagBits |= NULL_FLAG_MASK;
int position;
long mask;
- if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
+ if (local instanceof FieldBinding) {
+ position = local.id;
+ } else {
+ position = local.id + this.maxFieldCount;
+ }
+ if (position < BitCacheSize) {
// use bits
mask = 1L << position;
isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$
@@ -2077,8 +2237,13 @@ public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
return this;
}
-public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
- int position = local.id + this.maxFieldCount;
+public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
+ int position;
+ if (binding instanceof FieldBinding) {
+ position = binding.id;
+ } else {
+ position = binding.id + this.maxFieldCount;
+ }
int oldLength;
if (this.nullStatusChangedInAssert == null) {
this.nullStatusChangedInAssert = new int[position + 1];
@@ -2091,8 +2256,13 @@ public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local)
this.nullStatusChangedInAssert[position] = 1;
}
-public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
- int position = local.id + this.maxFieldCount;
+public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
+ int position;
+ if (binding instanceof FieldBinding) {
+ position = binding.id;
+ } else {
+ position = binding.id + this.maxFieldCount;
+ }
if(this.nullStatusChangedInAssert == null || position >= this.nullStatusChangedInAssert.length) {
return false;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index 3eb3cca..16c3b5c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -39,11 +39,13 @@ public class ClassScope extends Scope {
public TypeDeclaration referenceContext;
public TypeReference superTypeReference;
java.util.ArrayList deferredBoundChecks;
-
+ public int cumulativeFieldCount; // cumulative field count from all enclosing types, used to build unique field id's for member types.
+ public int localTypeFieldIdStart;
public ClassScope(Scope parent, TypeDeclaration context) {
super(Scope.CLASS_SCOPE, parent);
this.referenceContext = context;
this.deferredBoundChecks = null; // initialized if required
+ this.localTypeFieldIdStart = this.cumulativeFieldCount = 0;
}
void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) {
@@ -80,6 +82,8 @@ public class ClassScope extends Scope {
}
}
}
+ this.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
+ this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex;
connectMemberTypes();
buildFieldsAndMethods();
anonymousType.faultInTypesForFieldsAndMethods();
@@ -109,6 +113,23 @@ public class ClassScope extends Scope {
FieldBinding[] fieldBindings = new FieldBinding[count];
HashtableOfObject knownFieldNames = new HashtableOfObject(count);
count = 0;
+ ClassScope enclosingClass = this.enclosingClassScope();
+ if (enclosingClass != null) {
+ this.cumulativeFieldCount += enclosingClass.cumulativeFieldCount;
+ }
+// SourceTypeBinding enclosingSourceType = this.enclosingSourceType();
+// if (enclosingSourceType != null) {
+// ReferenceBinding superClassBinding = sourceType.superclass;
+// while (superClassBinding != null) {
+// FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields();
+// if (unResolvedFields != null) {
+// this.cumulativeFieldCount += unResolvedFields.length;
+// }
+// superClassBinding = superClassBinding.superclass();
+// }
+// ReferenceBinding[] superInterfacesBinding = enclosingSourceType.superInterfaces;
+// this.cumulativeFieldCount += findFieldCountFromSuperInterfaces(superInterfacesBinding);
+// }
for (int i = 0; i < size; i++) {
FieldDeclaration field = fields[i];
if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
@@ -116,7 +137,7 @@ public class ClassScope extends Scope {
// now this error reporting is moved into the parser itself. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=212713
} else {
FieldBinding fieldBinding = new FieldBinding(field, null, field.modifiers | ExtraCompilerModifiers.AccUnresolved, sourceType);
- fieldBinding.id = count;
+ fieldBinding.id = count + this.cumulativeFieldCount;
// field's type will be resolved when needed for top level types
checkAndSetModifiersForField(fieldBinding, field);
@@ -144,6 +165,7 @@ public class ClassScope extends Scope {
// remove duplicate fields
if (count != fieldBindings.length)
System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count);
+ this.cumulativeFieldCount += count;
sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type
sourceType.setFields(fieldBindings);
}
@@ -226,6 +248,8 @@ public class ClassScope extends Scope {
checkParameterizedTypeBounds();
checkParameterizedSuperTypeCollisions();
}
+ this.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
+ this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex;
buildFieldsAndMethods();
localType.faultInTypesForFieldsAndMethods();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
index 2c44d5a..dc36d91 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
@@ -16,11 +16,13 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.Constant;
public class FieldBinding extends VariableBinding {
public ReferenceBinding declaringClass;
public int compoundUseFlag = 0; // number or accesses via postIncrement or compoundAssignment
+ private int nullStatus;
protected FieldBinding() {
super(null, null, 0, null);
@@ -29,12 +31,14 @@ protected FieldBinding() {
public FieldBinding(char[] name, TypeBinding type, int modifiers, ReferenceBinding declaringClass, Constant constant) {
super(name, type, modifiers, constant);
this.declaringClass = declaringClass;
+ this.nullStatus = FlowInfo.UNKNOWN;
}
// special API used to change field declaring class for runtime visibility check
public FieldBinding(FieldBinding initialFieldBinding, ReferenceBinding declaringClass) {
super(initialFieldBinding.name, initialFieldBinding.type, initialFieldBinding.modifiers, initialFieldBinding.constant());
this.declaringClass = declaringClass;
this.id = initialFieldBinding.id;
+ this.nullStatus = FlowInfo.UNKNOWN;
setAnnotations(initialFieldBinding.getAnnotations());
}
/* API
@@ -386,4 +390,12 @@ public FieldDeclaration sourceField() {
}
return null;
}
+
+public int getNullStatusForStaticFinalField() {
+ return this.nullStatus;
+}
+
+public void setNullStatusForStaticFinalField(int nullStatusToMark) {
+ this.nullStatus = nullStatusToMark;
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index 9b83933..10cdb10 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -108,6 +108,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
import org.eclipse.jdt.internal.compiler.parser.JavadocTagConstants;
import org.eclipse.jdt.internal.compiler.parser.Parser;
@@ -286,18 +287,26 @@ public static int getIrritant(int problemID) {
return CompilerOptions.VarargsArgumentNeedCast;
case IProblem.NullLocalVariableReference:
+ case IProblem.NullFieldReference:
return CompilerOptions.NullReference;
case IProblem.PotentialNullLocalVariableReference:
case IProblem.PotentialNullMessageSendReference:
+ case IProblem.PotentialNullFieldReference:
return CompilerOptions.PotentialNullReference;
case IProblem.RedundantLocalVariableNullAssignment:
+ case IProblem.RedundantFieldNullAssignment:
case IProblem.RedundantNullCheckOnNonNullLocalVariable:
case IProblem.RedundantNullCheckOnNullLocalVariable:
case IProblem.NonNullLocalVariableComparisonYieldsFalse:
case IProblem.NullLocalVariableComparisonYieldsFalse:
case IProblem.NullLocalVariableInstanceofYieldsFalse:
+ case IProblem.NullFieldInstanceofYieldsFalse:
+ case IProblem.RedundantNullCheckOnNonNullField:
+ case IProblem.RedundantNullCheckOnNullField:
+ case IProblem.NonNullFieldComparisonYieldsFalse:
+ case IProblem.NullFieldComparisonYieldsFalse:
case IProblem.RedundantNullCheckOnNonNullMessageSend:
return CompilerOptions.RedundantNullCheck;
@@ -5072,110 +5081,158 @@ public void localVariableHiding(LocalDeclaration local, Binding hiddenVariable,
}
}
-public void localVariableNonNullComparedToNull(LocalVariableBinding local, ASTNode location) {
- int severity = computeSeverity(IProblem.NonNullLocalVariableComparisonYieldsFalse);
+public void variableNonNullComparedToNull(VariableBinding variable, ASTNode location) {
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.NonNullFieldComparisonYieldsFalse;
+ } else {
+ problem = IProblem.NonNullLocalVariableComparisonYieldsFalse;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name) };
+ String[] arguments = new String[] {new String(variable.name) };
this.handle(
- IProblem.NonNullLocalVariableComparisonYieldsFalse,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
-public void localVariableNullComparedToNonNull(LocalVariableBinding local, ASTNode location) {
- int severity = computeSeverity(IProblem.NullLocalVariableComparisonYieldsFalse);
+public void variableNullComparedToNonNull(VariableBinding variable, ASTNode location) {
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.NullFieldComparisonYieldsFalse;
+ } else {
+ problem = IProblem.NullLocalVariableComparisonYieldsFalse;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name) };
+ String[] arguments = new String[] {new String(variable.name) };
this.handle(
- IProblem.NullLocalVariableComparisonYieldsFalse,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
-public void localVariableNullInstanceof(LocalVariableBinding local, ASTNode location) {
- int severity = computeSeverity(IProblem.NullLocalVariableInstanceofYieldsFalse);
+public void variableNullInstanceof(VariableBinding variable, ASTNode location) {
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.NullFieldInstanceofYieldsFalse;
+ } else {
+ problem = IProblem.NullLocalVariableInstanceofYieldsFalse;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name) };
+ String[] arguments = new String[] {new String(variable.name) };
this.handle(
- IProblem.NullLocalVariableInstanceofYieldsFalse,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
-public void localVariableNullReference(LocalVariableBinding local, ASTNode location) {
- int severity = computeSeverity(IProblem.NullLocalVariableReference);
+public void variableNullReference(VariableBinding variable, ASTNode location) {
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.NullFieldReference;
+ } else {
+ problem = IProblem.NullLocalVariableReference;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name) };
+ String[] arguments = new String[] {new String(variable.name) };
this.handle(
- IProblem.NullLocalVariableReference,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
-public void localVariablePotentialNullReference(LocalVariableBinding local, ASTNode location) {
- int severity = computeSeverity(IProblem.PotentialNullLocalVariableReference);
+public void variablePotentialNullReference(VariableBinding variable, ASTNode location) {
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.PotentialNullFieldReference;
+ } else {
+ problem = IProblem.PotentialNullLocalVariableReference;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name)};
+ String[] arguments = new String[] {new String(variable.name)};
this.handle(
- IProblem.PotentialNullLocalVariableReference,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
-public void localVariableRedundantCheckOnNonNull(LocalVariableBinding local, ASTNode location) {
- int severity = computeSeverity(IProblem.RedundantNullCheckOnNonNullLocalVariable);
+public void variableRedundantCheckOnNonNull(VariableBinding variable, ASTNode location) {
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.RedundantNullCheckOnNonNullField;
+ } else {
+ problem = IProblem.RedundantNullCheckOnNonNullLocalVariable;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name) };
+ String[] arguments = new String[] {new String(variable.name) };
this.handle(
- IProblem.RedundantNullCheckOnNonNullLocalVariable,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
-public void localVariableRedundantCheckOnNull(LocalVariableBinding local, ASTNode location) {
- int severity = computeSeverity(IProblem.RedundantNullCheckOnNullLocalVariable);
+public void variableRedundantCheckOnNull (VariableBinding variable, ASTNode location) {
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.RedundantNullCheckOnNullField;
+ } else {
+ problem = IProblem.RedundantNullCheckOnNullLocalVariable;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name) };
+ String[] arguments = new String[] {new String(variable.name) };
this.handle(
- IProblem.RedundantNullCheckOnNullLocalVariable,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
-public void localVariableRedundantNullAssignment(LocalVariableBinding local, ASTNode location) {
+public void variableRedundantNullAssignment (VariableBinding variable, ASTNode location) {
if ((location.bits & ASTNode.FirstAssignmentToLocal) != 0) // https://bugs.eclipse.org/338303 - Warning about Redundant assignment conflicts with definite assignment
return;
- int severity = computeSeverity(IProblem.RedundantLocalVariableNullAssignment);
+ int problem;
+ if (variable instanceof FieldBinding) {
+ problem = IProblem.RedundantFieldNullAssignment;
+ } else {
+ problem = IProblem.RedundantLocalVariableNullAssignment;
+ }
+ int severity = computeSeverity(problem);
if (severity == ProblemSeverities.Ignore) return;
- String[] arguments = new String[] {new String(local.name) };
+ String[] arguments = new String[] {new String(variable.name) };
this.handle(
- IProblem.RedundantLocalVariableNullAssignment,
+ problem,
arguments,
arguments,
severity,
- nodeSourceStart(local, location),
- nodeSourceEnd(local, location));
+ nodeSourceStart(variable, location),
+ nodeSourceEnd(variable, location));
}
public void methodMustOverride(AbstractMethodDeclaration method, long complianceLevel) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index d05ebd2..dba1762 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -581,6 +581,16 @@
### MORE GENERICS
660 = Unused type arguments for the non generic constructor {0}({1}) of type {2}; it should not be parameterized with arguments <{3}>
+### NULL ANALYSIS FOR FIELDS
+670 = Null pointer access: The field {0} can only be null at this location
+671 = Potential null pointer access: The field {0} may be null at this location
+672 = Redundant null check: The field {0} can only be null at this location
+673 = Null comparison always yields false: The field {0} can only be null at this location
+674 = Redundant null check: The field {0} cannot be null at this location
+675 = Null comparison always yields false: The field {0} cannot be null at this location
+676 = Redundant assignment: The field {0} can only be null at this location
+677 = instanceof always yields false: The field {0} can only be null at this location
+
### CORRUPTED BINARIES
700 = The class file {0} contains a signature ''{1}'' ill-formed at position {2}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
index 52c943d..20a3d22 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at