Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 206572 Details for
Bug 247564
[compiler][null] Detecting null field reference
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
same patch rebased on top of bug 186342 patch v9 (corrected)
Bug_247564-rebased2.patch (text/plain), 158.61 KB, created by
Stephan Herrmann
on 2011-11-08 05:15:05 EST
(
hide
)
Description:
same patch rebased on top of bug 186342 patch v9 (corrected)
Filename:
MIME Type:
Creator:
Stephan Herrmann
Created:
2011-11-08 05:15:05 EST
Size:
158.61 KB
patch
obsolete
>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 9e23bb3..2534492 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 >@@ -722,6 +722,7 @@ > 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)); >@@ -735,6 +736,9 @@ > expectedProblemAttributes.put("NotVisibleMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); > expectedProblemAttributes.put("NotVisibleType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("NullAnnotationNameMustBeQualified", new ProblemAttributes(CategorizedProblem.CAT_BUILDPATH)); >+ 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)); >@@ -778,6 +782,7 @@ > 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)); >@@ -787,9 +792,12 @@ > 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("RedundantNullCheckOnNullField", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("RedundantNullCheckOnNonNullMessageSend", 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)); >@@ -1405,6 +1413,7 @@ > 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)); >@@ -1417,6 +1426,9 @@ > 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)); >@@ -1458,6 +1470,7 @@ > 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("PublicClassMustMatchFileName", SKIP); > expectedProblemAttributes.put("RawMemberTypeCannotBeParameterized", SKIP); >@@ -1466,8 +1479,11 @@ > 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("RedundantNullCheckOnNonNullField", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); > expectedProblemAttributes.put("RedundantNullCheckOnNonNullLocalVariable", 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.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 @@ > 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 21a0d02..27f70a5 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 @@ > " 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 @@ > " 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 @@ > " 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 @@ > " }\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 @@ > " }\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" > ); > } > >@@ -15396,4 +15391,547 @@ > "",/* 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 9ff2c32..da8951d 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 >@@ -1267,6 +1267,26 @@ > /** @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 16e7fe3..882f974 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 >@@ -41,14 +41,15 @@ > // 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? >@@ -59,17 +60,23 @@ > 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; > } >@@ -223,4 +230,7 @@ > 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 @@ > 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.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 @@ > 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 296364d..26d736a 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,23 +39,23 @@ > scope.problemReporter().messageSendRedundantCheckOnNonNull(rightMessage.binding, rightMessage); > } > >- 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, this.right.nullStatus(flowInfo), 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, this.left.nullStatus(flowInfo), 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) { > flowContext.recordUsingNullReference(scope, local, reference, > FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo); > initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set >- initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set >+ initsWhenFalse.markAsComparedEqualToNonNull(local ); // from thereon it is set > } else { > flowContext.recordUsingNullReference(scope, local, reference, > FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo); >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.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 @@ > * @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 @@ > 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, 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 @@ > .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.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 @@ > } > 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 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 456370a..8532840 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 >@@ -114,6 +114,9 @@ > // 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 a2cdd89..0abcc5d 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 >@@ -807,6 +807,15 @@ > 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)) { >@@ -859,11 +868,10 @@ > } > 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 975ca3b..3a02b08 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 >@@ -77,13 +77,13 @@ > > /** 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 @@ > // 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 @@ > // 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 @@ > } > 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 @@ > } > } 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 @@ > 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 @@ > 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 @@ > } > 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 @@ > } > } > >+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 @@ > > 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 @@ > && 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 @@ > || 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 @@ > 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 @@ > 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 fbad42e..9953f73 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 >@@ -31,7 +31,7 @@ > VariableBinding[] finalVariables; > int assignCount; > >- LocalVariableBinding[] nullLocals; >+ VariableBinding[] nullVariables; > Expression[] nullReferences; > int[] nullCheckTypes; > int nullCount; >@@ -86,9 +86,9 @@ > 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); > > } >@@ -97,18 +97,18 @@ > 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; >@@ -122,27 +122,27 @@ > 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)) { >@@ -150,14 +150,14 @@ > 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; >@@ -166,11 +166,11 @@ > 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: >@@ -225,7 +225,7 @@ > 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 >@@ -239,14 +239,14 @@ > 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); >@@ -258,11 +258,11 @@ > 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); >@@ -270,34 +270,34 @@ > 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; >@@ -309,7 +309,7 @@ > return; > } > if (flowInfo.canOnlyBeNull(local)) { >- scope.problemReporter().localVariableNullReference(local, reference); >+ scope.problemReporter().variableNullReference(local, reference); > return; > } > break; >@@ -324,14 +324,14 @@ > 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); >@@ -348,11 +348,11 @@ > 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); >@@ -360,34 +360,34 @@ > 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; >@@ -396,11 +396,11 @@ > 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)) { >@@ -432,17 +432,17 @@ > } > } > >-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, >@@ -451,7 +451,7 @@ > 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 2e7737b..0653f32 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 >@@ -585,7 +585,7 @@ > * 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 > } >@@ -628,7 +628,7 @@ > * 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)) { >@@ -640,14 +640,14 @@ > 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); >@@ -667,11 +667,11 @@ > 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); >@@ -679,34 +679,34 @@ > 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; >@@ -717,11 +717,11 @@ > 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.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 @@ > } > > /** >- * 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 @@ > 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 @@ > 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 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 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 @@ > * 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 3e9d4cd..68d6560 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 >@@ -45,7 +45,7 @@ > VariableBinding finalVariables[]; > int assignCount = 0; > >- LocalVariableBinding[] nullLocals; >+ VariableBinding[] nullVariables; > Expression[] nullReferences; > int[] nullCheckTypes; > int nullCount; >@@ -141,7 +141,7 @@ > 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]) { >@@ -151,11 +151,11 @@ > 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; >@@ -167,11 +167,11 @@ > 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; >@@ -180,11 +180,11 @@ > 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; >@@ -199,27 +199,27 @@ > 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)) { >@@ -227,14 +227,14 @@ > 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; >@@ -244,7 +244,7 @@ > case MAY_NULL: > if (flowInfo.isDefinitelyNull(local)) { > this.nullReferences[i] = null; >- scope.problemReporter().localVariableNullReference(local, expression); >+ scope.problemReporter().variableNullReference(local, expression); > continue; > } > break; >@@ -263,7 +263,7 @@ > 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: >@@ -271,11 +271,11 @@ > 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; >@@ -290,27 +290,27 @@ > 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)) { >@@ -318,14 +318,14 @@ > 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; >@@ -335,12 +335,12 @@ > 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; >@@ -472,27 +472,27 @@ > 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)) { >@@ -504,14 +504,14 @@ > 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); >@@ -520,14 +520,14 @@ > } 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); >@@ -571,11 +571,11 @@ > 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); >@@ -583,34 +583,34 @@ > 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; >@@ -629,11 +629,11 @@ > 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 @@ > 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 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 @@ > } > // 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 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 @@ > * 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 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 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.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 @@ > 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 @@ > & (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 @@ > & (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 @@ > 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 @@ > 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 @@ > & (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 @@ > & (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 @@ > } > > // 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 @@ > } > > // 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 @@ > & (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 @@ > & (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 @@ > & (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 @@ > 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 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 @@ > 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 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 @@ > */ > // 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 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 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 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 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 @@ > 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 @@ > 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 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 @@ > } > } > } >+ this.cumulativeFieldCount += outerMostMethodScope().analysisIndex; >+ this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex; > connectMemberTypes(); > buildFieldsAndMethods(); > anonymousType.faultInTypesForFieldsAndMethods(); >@@ -109,6 +113,23 @@ > 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 @@ > // 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 @@ > // 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 @@ > 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.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 @@ > 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 @@ > } > 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 efa3712..0d83caf 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 >@@ -107,6 +107,7 @@ > 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; >@@ -285,19 +286,27 @@ > return CompilerOptions.VarargsArgumentNeedCast; > > case IProblem.NullLocalVariableReference: >+ case IProblem.NullFieldReference: > return CompilerOptions.NullReference; > > case IProblem.PotentialNullLocalVariableReference: >+ case IProblem.PotentialNullFieldReference: > case IProblem.PotentialNullMessageSendReference: > 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.RedundantNullCheckOnNonNullMessageSend: >+ case IProblem.NullFieldInstanceofYieldsFalse: >+ case IProblem.RedundantNullCheckOnNonNullField: >+ case IProblem.RedundantNullCheckOnNullField: >+ case IProblem.NonNullFieldComparisonYieldsFalse: >+ case IProblem.NullFieldComparisonYieldsFalse: > return CompilerOptions.RedundantNullCheck; > > case IProblem.RequiredNonNullButProvidedNull: >@@ -5028,110 +5037,158 @@ > } > } > >-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 00e30c8..edc2816 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 >@@ -580,6 +580,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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 247564
:
185536
|
185729
|
186938
|
187094
|
188023
|
206514
|
206570
| 206572 |
207019
|
209475
|
209486
|
209552
|
209734
|
209741
|
209759
|
209774
|
209775