### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java,v retrieving revision 1.2 diff -u -r1.2 NullReferenceImplTests.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java 10 May 2006 18:07:27 -0000 1.2 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java 25 Sep 2006 11:01:02 -0000 @@ -651,7 +651,9 @@ isPotentiallyNull = state.isPotentiallyNull(TestLocalVariableBinding.local0), isPotentiallyUnknown = state.isPotentiallyUnknown(TestLocalVariableBinding.local0), isProtectedNonNull = state.isProtectedNonNull(TestLocalVariableBinding.local0), - isProtectedNull = state.isProtectedNull(TestLocalVariableBinding.local0); + isProtectedNull = state.isProtectedNull(TestLocalVariableBinding.local0), + cannotBeNull = state.cannotBeNull(TestLocalVariableBinding.local0), + canOnlyBeNull = state.canOnlyBeNull(TestLocalVariableBinding.local0); if (isDefinitelyNonNull && (isDefinitelyNull || isDefinitelyUnknown || isPotentiallyNull @@ -688,7 +690,11 @@ && !(isDefinitelyNonNull || isDefinitelyNull || isDefinitelyUnknown || isPotentiallyNull || isPotentiallyUnknown || isProtectedNonNull - || isProtectedNull)) { + || isProtectedNull) + || cannotBeNull != (isProtectedNonNull || + isDefinitelyNonNull) + || canOnlyBeNull != (isProtectedNull || + isDefinitelyNull)) { if (failures == 0) { System.out.println(header); } @@ -714,7 +720,9 @@ isPotentiallyNull = state.isPotentiallyNull(TestLocalVariableBinding.local64), isPotentiallyUnknown = state.isPotentiallyUnknown(TestLocalVariableBinding.local64), isProtectedNonNull = state.isProtectedNonNull(TestLocalVariableBinding.local64), - isProtectedNull = state.isProtectedNull(TestLocalVariableBinding.local64); + isProtectedNull = state.isProtectedNull(TestLocalVariableBinding.local64), + cannotBeNull = state.cannotBeNull(TestLocalVariableBinding.local64), + canOnlyBeNull = state.canOnlyBeNull(TestLocalVariableBinding.local64); if (isDefinitelyNonNull && (isDefinitelyNull || isDefinitelyUnknown || isPotentiallyNull @@ -751,7 +759,11 @@ && !(isDefinitelyNonNull || isDefinitelyNull || isDefinitelyUnknown || isPotentiallyNull || isPotentiallyUnknown || isProtectedNonNull - || isProtectedNull)) { + || isProtectedNull) + || cannotBeNull != (isProtectedNonNull || + isDefinitelyNonNull) + || canOnlyBeNull != (isProtectedNull || + isDefinitelyNull)) { if (failures == 0) { System.out.println(header); } 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.40 diff -u -r1.40 NullReferenceTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 25 Sep 2006 10:28:20 -0000 1.40 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 25 Sep 2006 11:01:05 -0000 @@ -4322,6 +4322,133 @@ ""); } +// null analysis -- try/finally +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=149665 +// incorrect analysis within try finally with an embedded && expression +public void test0521_try_finally() { + this.runConformTest( + new String[] { + "X.java", + "public class X\n" + + "{\n" + + " X m;\n" + + " public void foo() {\n" + + " for(int j = 0; j < 10; j++) {\n" + + " try {\n" + + " j++;\n" + + " } finally {\n" + + " X t = m;\n" + + " if( t != null && t.bar()) {\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " boolean bar() {\n" + + " return false;\n" + + " }\n" + + "}"}, + ""); +} + +//null analysis -- try/finally +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=149665 +//variant +public void test0522_try_finally() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X\n" + + "{\n" + + " X m;\n" + + " public void foo() {\n" + + " for(int j = 0; j < 10; j++) {\n" + + " try {\n" + + " j++;\n" + + " } finally {\n" + + " X t = null;\n" + + " if(t.bar()) {\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " boolean bar() {\n" + + " return false;\n" + + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 10)\n" + + " if(t.bar()) {\n" + + " ^\n" + + "The variable t can only be null; it was either set to null or checked for null when last used\n" + + "----------\n"); +} + +// null analysis -- try/finally +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=149665 +// variant +public void test0523_try_finally() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X\n" + + "{\n" + + " X m;\n" + + " public void foo() {\n" + + " for(int j = 0; j < 10; j++) {\n" + + " try {\n" + + " j++;\n" + + " } finally {\n" + + " X t = m;\n" + + " if(t == null ? false : (t == null ? false : t.bar())) {\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " boolean bar() {\n" + + " return false;\n" + + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 10)\n" + + " if(t == null ? false : (t == null ? false : t.bar())) {\n" + + " ^\n" + + "The variable t cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + + "----------\n"); +} + +// null analysis -- try/finally +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=149665 +// variant +public void test0524_try_finally() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X\n" + + "{\n" + + " X m;\n" + + " public void foo() {\n" + + " for(int j = 0; j < 10; j++) {\n" + + " try {\n" + + " j++;\n" + + " } finally {\n" + + " X t = m;\n" + + " if(t != null ? false : (t == null ? false : t.bar())) {\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " boolean bar() {\n" + + " return false;\n" + + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 10)\n" + + " if(t != null ? false : (t == null ? false : t.bar())) {\n" + + " ^\n" + + "The variable t can only be null; it was either set to null or checked for null when last used\n" + + "----------\n"); +} + // null analysis -- try/catch public void test0550_try_catch() { this.runConformTest( #P org.eclipse.jdt.core 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.32 diff -u -r1.32 FlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 26 Apr 2006 09:17:30 -0000 1.32 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 25 Sep 2006 11:01:07 -0000 @@ -62,6 +62,28 @@ // if (initsWhenTrue.equals(initsWhenFalse)) return initsWhenTrue; -- could optimize if #equals is defined return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse); } + +/** + * Check whether a given 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 + */ +// WORK (maxime) implement fast version for UnconditionalFlowInfo +public boolean cannotBeNull(LocalVariableBinding local) { + return isDefinitelyNonNull(local) || isProtectedNonNull(local); +} + +/** + * 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 + */ +// WORK (maxime) implement fast version for UnconditionalFlowInfo +public boolean canOnlyBeNull(LocalVariableBinding local) { + return isDefinitelyNull(local) || isProtectedNull(local); +} /** * Return a deep copy of the current instance. Index: compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java,v retrieving revision 1.19 diff -u -r1.19 FinallyFlowContext.java --- compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java 28 Mar 2006 20:32:37 -0000 1.19 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java 25 Sep 2006 11:01:07 -0000 @@ -91,7 +91,7 @@ if (nullCheckTypes[i] == CAN_ONLY_NULL_NON_NULL) { scope.problemReporter().localVariableCannotBeNull(local, expression); } - return; + return; // WORK wrong, test second variable! } if (flowInfo.isProtectedNull(local)) { scope.problemReporter().localVariableCanOnlyBeNull(local, expression); @@ -193,22 +193,22 @@ switch (checkType) { case CAN_ONLY_NULL_NON_NULL : case CAN_ONLY_NULL: - if (flowInfo.isProtectedNonNull(local)) { + if (flowInfo.cannotBeNull(local)) { if (checkType == CAN_ONLY_NULL_NON_NULL) { scope.problemReporter().localVariableCannotBeNull(local, reference); } return; } - if (flowInfo.isProtectedNull(local)) { + if (flowInfo.canOnlyBeNull(local)) { scope.problemReporter().localVariableCanOnlyBeNull(local, reference); return; } break; case MAY_NULL : - if (flowInfo.isProtectedNonNull(local)) { + if (flowInfo.cannotBeNull(local)) { return; } - if (flowInfo.isProtectedNull(local)) { + if (flowInfo.canOnlyBeNull(local)) { scope.problemReporter().localVariableCanOnlyBeNull(local, reference); return; }