### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java,v retrieving revision 1.89 diff -u -r1.89 Assignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 14 Jul 2010 10:37:15 -0000 1.89 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 17 Jul 2010 15:38:13 -0000 @@ -55,6 +55,9 @@ case FlowInfo.NON_NULL : flowInfo.markAsDefinitelyNonNull(local); break; + case FlowInfo.POTENTIALLY_NULL : + flowInfo.markAsPotentiallyNull(local); + break; default: flowInfo.markAsDefinitelyUnknown(local); } @@ -66,6 +69,9 @@ case FlowInfo.NON_NULL : flowContext.initsOnFinally.markAsDefinitelyNonNull(local); break; + case FlowInfo.POTENTIALLY_NULL : + flowContext.initsOnFinally.markAsPotentiallyNull(local); + break; default: flowContext.initsOnFinally.markAsDefinitelyUnknown(local); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java,v retrieving revision 1.128 diff -u -r1.128 Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 7 Jan 2010 20:18:49 -0000 1.128 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 17 Jul 2010 15:38:14 -0000 @@ -829,11 +829,11 @@ this.bits |= ASTNode.IsNonNull; } - public int nullStatus(FlowInfo flowInfo) { +public int nullStatus(FlowInfo flowInfo) { - if (/* (this.bits & IsNonNull) != 0 || */ - this.constant != null && this.constant != Constant.NotAConstant) - return FlowInfo.NON_NULL; // constant expression cannot be null + if (/* (this.bits & IsNonNull) != 0 || */ + this.constant != null && this.constant != Constant.NotAConstant) + return FlowInfo.NON_NULL; // constant expression cannot be null LocalVariableBinding local = localVariableBinding(); if (local != null) { @@ -841,6 +841,8 @@ return FlowInfo.NULL; if (flowInfo.isDefinitelyNonNull(local)) return FlowInfo.NON_NULL; + if (flowInfo.isPotentiallyNull(local)) + return FlowInfo.POTENTIALLY_NULL; return FlowInfo.UNKNOWN; } return FlowInfo.NON_NULL; Index: compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java,v retrieving revision 1.71 diff -u -r1.71 LocalDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 23 Oct 2009 15:15:26 -0000 1.71 +++ compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 17 Jul 2010 15:38:15 -0000 @@ -59,6 +59,9 @@ case FlowInfo.NON_NULL : flowInfo.markAsDefinitelyNonNull(this.binding); break; + case FlowInfo.POTENTIALLY_NULL : + flowInfo.markAsPotentiallyNull(this.binding); + break; default: flowInfo.markAsDefinitelyUnknown(this.binding); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java,v retrieving revision 1.117 diff -u -r1.117 SingleNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 7 Apr 2010 12:47:50 -0000 1.117 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 17 Jul 2010 15:38:16 -0000 @@ -774,6 +774,8 @@ return FlowInfo.NULL; if (flowInfo.isDefinitelyNonNull(local)) return FlowInfo.NON_NULL; + if (flowInfo.isPotentiallyNull(local)) + return FlowInfo.POTENTIALLY_NULL; return FlowInfo.UNKNOWN; } } Index: compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java,v retrieving revision 1.41 diff -u -r1.41 FlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 24 Feb 2010 20:12:41 -0000 1.41 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 17 Jul 2010 15:38:17 -0000 @@ -23,6 +23,7 @@ public final static int UNKNOWN = 0; public final static int NULL = 1; public final static int NON_NULL = -1; + public final static int POTENTIALLY_NULL = 2; public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization static { @@ -244,6 +245,8 @@ * Record a local got definitely assigned to null. */ abstract public void markAsDefinitelyNull(LocalVariableBinding local); + + public void markAsPotentiallyNull(LocalVariableBinding local) { /* empty default impl. */ } /** * Record a local got definitely assigned. Index: compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java,v retrieving revision 1.65 diff -u -r1.65 UnconditionalFlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 24 Feb 2010 20:12:40 -0000 1.65 +++ compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 17 Jul 2010 15:38:20 -0000 @@ -1284,6 +1284,30 @@ } } +public void markAsPotentiallyNull(LocalVariableBinding local) { + if (this != DEAD_END) { + this.tagBits |= NULL_FLAG_MASK; + int position; + long mask; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + // use bits + this.nullBit1 &= ~(mask = 1L << position); + this.nullBit2 |= mask; + this.nullBit3 &= ~mask; + this.nullBit4 &= ~mask; + } else { + // use extra vector + int vectorIndex ; + this.extra[2][vectorIndex = (position / BitCacheSize) - 1] + &= ~(mask = 1L << (position % BitCacheSize)); + this.extra[3][vectorIndex] |= mask; + this.extra[4][vectorIndex] &= (mask = ~mask); + this.extra[5][vectorIndex] &= mask; + } + + } +} + /** * Mark a local as having been assigned to an unknown value. * @param local the local to mark #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java,v retrieving revision 1.95 diff -u -r1.95 NullReferenceTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 16 Mar 2010 14:36:08 -0000 1.95 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 17 Jul 2010 15:38:35 -0000 @@ -11662,4 +11662,134 @@ "----------\n", JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); } + +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +// LocalDeclaration +public void testBug292478() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " void foo(Object o) {\n" + + " if (o != null) {/* */}\n" + + " Object p = o;\n" + + " p.toString();\n" + // complain here + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 5)\n" + + " p.toString();\n" + + " ^\n" + + "Potential null pointer access: The variable p may be null at this location\n" + + "----------\n", + JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); +} + +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +// Assignment +public void testBug292478a() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " void foo(Object o) {\n" + + " Object p;" + + " if (o != null) {/* */}\n" + + " p = o;\n" + + " p.toString();\n" + // complain here + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 5)\n" + + " p.toString();\n" + + " ^\n" + + "Potential null pointer access: The variable p may be null at this location\n" + + "----------\n", + JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); +} + +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +//Assignment after definite null +public void testBug292478b() { +this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " void foo(Object o) {\n" + + " Object p = null;\n" + + " if (o != null) {/* */}\n" + + " p = o;\n" + + " p.toString();\n" + // complain here + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 6)\n" + + " p.toString();\n" + + " ^\n" + + "Potential null pointer access: The variable p may be null at this location\n" + + "----------\n", + JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +//Assignment after definite null - many locals +public void testBug292478c() { +this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " void foo(Object o) {\n" + + " int i00, i01, i02, i03, i04, i05, i06, i07, i08, i09;\n" + + " int i10, i11, i12, i13, i14, i15, i16, i17, i18, i19;\n" + + " int i20, i21, i22, i23, i24, i25, i26, i27, i28, i29;\n" + + " int i30, i31, i32, i33, i34, i35, i36, i37, i38, i39;\n" + + " int i40, i41, i42, i43, i44, i45, i46, i47, i48, i49;\n" + + " int i50, i51, i52, i53, i54, i55, i56, i57, i58, i59;\n" + + " int i60, i61, i62, i63, i64, i65, i66, i67, i68, i69;\n" + + " Object p = null;\n" + + " if (o != null) {/* */}\n" + + " p = o;\n" + + " p.toString();\n" + // complain here + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 13)\n" + + " p.toString();\n" + + " ^\n" + + "Potential null pointer access: The variable p may be null at this location\n" + + "----------\n", + JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +//Assignment affects initsOnFinally +public void testBug292478d() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " X bar() {\n" + + " return null;\n" + + " }\n" + + " Object foo() {\n" + + " X x = null;\n" + + " X y = new X();\n" + + " X u = null;\n" + + " try {\n" + + " u = bar();\n" + + " x = bar();\n" + + " if (x==null) { }\n" + + " y = x;\n" + // this makes y potentially null + " if (x==null) { y=bar();} else { y=new X(); }\n" + + " return x;\n" + + " } finally {\n" + + " y.toString();\n" + // must complain against potentially null, although normal exist of tryBlock says differently (unknown or non-null) + " }\n" + + " }\n" + + "}\n"}, + "----------\n" + + "1. ERROR in X.java (at line 17)\n" + + " y.toString();\n" + + " ^\n" + + "Potential null pointer access: The variable y may be null at this location\n" + + "----------\n"); +} } \ No newline at end of file