### 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.91 diff -u -r1.91 Assignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 31 Aug 2010 14:58:05 -0000 1.91 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 9 Sep 2010 15:34:35 -0000 @@ -53,34 +53,9 @@ .analyseAssignment(currentScope, flowContext, flowInfo, this, false) .unconditionalInits(); if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { - switch(nullStatus) { - case FlowInfo.NULL : - flowInfo.markAsDefinitelyNull(local); - break; - case FlowInfo.NON_NULL : - flowInfo.markAsDefinitelyNonNull(local); - break; - case FlowInfo.POTENTIALLY_NULL : - flowInfo.markAsPotentiallyNull(local); - break; - default: - flowInfo.markAsDefinitelyUnknown(local); - } - if (flowContext.initsOnFinally != null) { - switch(nullStatus) { - case FlowInfo.NULL : - flowContext.initsOnFinally.markAsDefinitelyNull(local); - break; - case FlowInfo.NON_NULL : - flowContext.initsOnFinally.markAsDefinitelyNonNull(local); - break; - case FlowInfo.POTENTIALLY_NULL : - flowContext.initsOnFinally.markAsPotentiallyNull(local); - break; - default: - flowContext.initsOnFinally.markAsDefinitelyUnknown(local); - } - } + flowInfo.markNullStatus(local, nullStatus); + if (flowContext.initsOnFinally != null) + flowContext.initsOnFinally.markNullStatus(local, nullStatus); } return flowInfo; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java,v retrieving revision 1.96 diff -u -r1.96 ConditionalExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java 1 Sep 2010 15:43:21 -0000 1.96 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java 9 Sep 2010 15:34:35 -0000 @@ -7,7 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephen Herrmann - Contribution for bug 133125 + * Stephen Herrmann - Contributions for bugs 133125, 292478 *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -319,20 +319,19 @@ if (ifTrueNullStatus == ifFalseNullStatus) { return ifTrueNullStatus; } - // is there a chance of null? -> potentially null + // is there a chance of null (or non-null)? -> potentially null etc. // https://bugs.eclipse.org/bugs/show_bug.cgi?id=133125 - switch (ifTrueNullStatus) { - case FlowInfo.NULL: - case FlowInfo.POTENTIALLY_NULL: - return FlowInfo.POTENTIALLY_NULL; - } - switch (ifFalseNullStatus) { - case FlowInfo.NULL: - case FlowInfo.POTENTIALLY_NULL: - return FlowInfo.POTENTIALLY_NULL; - } + int status = 0; + int combinedStatus = ifTrueNullStatus|ifFalseNullStatus; + if ((combinedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL)) != 0) + status |= FlowInfo.POTENTIALLY_NULL; + if ((combinedStatus & (FlowInfo.NON_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) + status |= FlowInfo.POTENTIALLY_NON_NULL; + if ((combinedStatus & (FlowInfo.UNKNOWN|FlowInfo.POTENTIALLY_UNKNOWN)) != 0) + status |= FlowInfo.POTENTIALLY_UNKNOWN; + if (status > 0) + return status; return FlowInfo.UNKNOWN; - // cannot decide which branch to take, and they disagree } public Constant optimizedBooleanConstant() { 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.129 diff -u -r1.129 Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 31 Aug 2010 14:58:05 -0000 1.129 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 9 Sep 2010 15:34:35 -0000 @@ -837,15 +837,8 @@ return FlowInfo.NON_NULL; // constant expression cannot be null LocalVariableBinding local = localVariableBinding(); - if (local != null) { - if (flowInfo.isDefinitelyNull(local)) - return FlowInfo.NULL; - if (flowInfo.isDefinitelyNonNull(local)) - return FlowInfo.NON_NULL; - if (flowInfo.isPotentiallyNull(local)) - return FlowInfo.POTENTIALLY_NULL; - return FlowInfo.UNKNOWN; - } + if (local != null) + return flowInfo.nullStatus(local); 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.73 diff -u -r1.73 LocalDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 31 Aug 2010 14:58:05 -0000 1.73 +++ compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 9 Sep 2010 15:34:35 -0000 @@ -57,19 +57,7 @@ } flowInfo.markAsDefinitelyAssigned(this.binding); if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) { - switch(nullStatus) { - case FlowInfo.NULL : - flowInfo.markAsDefinitelyNull(this.binding); - break; - case FlowInfo.NON_NULL : - flowInfo.markAsDefinitelyNonNull(this.binding); - break; - case FlowInfo.POTENTIALLY_NULL : - flowInfo.markAsPotentiallyNull(this.binding); - break; - default: - flowInfo.markAsDefinitelyUnknown(this.binding); - } + flowInfo.markNullStatus(this.binding, nullStatus); // no need to inform enclosing try block since its locals won't get // known by the finally block } 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.118 diff -u -r1.118 SingleNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 31 Aug 2010 14:58:05 -0000 1.118 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 9 Sep 2010 15:34:35 -0000 @@ -770,15 +770,8 @@ return FlowInfo.UNKNOWN; case Binding.LOCAL : // reading a local variable LocalVariableBinding local = (LocalVariableBinding) this.binding; - if (local != null) { - if (flowInfo.isDefinitelyNull(local)) - return FlowInfo.NULL; - if (flowInfo.isDefinitelyNonNull(local)) - return FlowInfo.NON_NULL; - if (flowInfo.isPotentiallyNull(local)) - return FlowInfo.POTENTIALLY_NULL; - return FlowInfo.UNKNOWN; - } + if (local != null) + return flowInfo.nullStatus(local); } return FlowInfo.NON_NULL; // never get there } Index: compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java,v retrieving revision 1.31 diff -u -r1.31 ConditionalFlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java 31 Aug 2010 14:58:05 -0000 1.31 +++ compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java 9 Sep 2010 15:34:35 -0000 @@ -157,9 +157,19 @@ this.initsWhenFalse.markAsDefinitelyNull(local); } -public void markAsPotentiallyNull(LocalVariableBinding local) { - this.initsWhenTrue.markAsPotentiallyNull(local); - this.initsWhenFalse.markAsPotentiallyNull(local); +public void resetNullInfo(LocalVariableBinding local) { + this.initsWhenTrue.resetNullInfo(local); + this.initsWhenFalse.resetNullInfo(local); +} + +public void markPotentiallyNullBit(LocalVariableBinding local) { + this.initsWhenTrue.markPotentiallyNullBit(local); + this.initsWhenFalse.markPotentiallyNullBit(local); +} + +public void markPotentiallyNonNullBit(LocalVariableBinding local) { + this.initsWhenTrue.markPotentiallyNonNullBit(local); + this.initsWhenFalse.markPotentiallyNonNullBit(local); } public void markAsDefinitelyUnknown(LocalVariableBinding local) { @@ -167,6 +177,11 @@ this.initsWhenFalse.markAsDefinitelyUnknown(local); } +public void markPotentiallyUnknownBit(LocalVariableBinding local) { + this.initsWhenTrue.markPotentiallyUnknownBit(local); + this.initsWhenFalse.markPotentiallyUnknownBit(local); +} + public FlowInfo setReachMode(int reachMode) { if (reachMode == REACHABLE) { this.tagBits &= ~UNREACHABLE; 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.43 diff -u -r1.43 FlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 31 Aug 2010 14:58:05 -0000 1.43 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 9 Sep 2010 15:34:35 -0000 @@ -23,10 +23,12 @@ public final static int UNREACHABLE = 1; public final static int NULL_FLAG_MASK = 2; - 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 final static int UNKNOWN = 1; + public final static int NULL = 2; + public final static int NON_NULL = 4; + public final static int POTENTIALLY_UNKNOWN = 8; + public final static int POTENTIALLY_NULL = 16; + public final static int POTENTIALLY_NON_NULL = 32; public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization static { @@ -248,11 +250,26 @@ * Record a local got definitely assigned to null. */ abstract public void markAsDefinitelyNull(LocalVariableBinding local); - + /** - * Record a local may have got assigned to null. + * Reset all null-information about a given local. */ - abstract public void markAsPotentiallyNull(LocalVariableBinding local); + abstract public void resetNullInfo(LocalVariableBinding local); + + /** + * Record a local may have got assigned to unknown (set the bit on existing info). + */ + abstract public void markPotentiallyUnknownBit(LocalVariableBinding local); + + /** + * Record a local may have got assigned to null (set the bit on existing info). + */ + abstract public void markPotentiallyNullBit(LocalVariableBinding local); + + /** + * Record a local may have got assigned to non-null (set the bit on existing info). + */ + abstract public void markPotentiallyNonNullBit(LocalVariableBinding local); /** * Record a local got definitely assigned. @@ -265,6 +282,61 @@ abstract public void markAsDefinitelyUnknown(LocalVariableBinding local); /** + * Mark the null status of the given local according to the given status + * @param local + * @param nullStatus bitset of FLowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL + */ +public void markNullStatus(LocalVariableBinding local, int nullStatus) { + switch(nullStatus) { + // definite status? + case FlowInfo.UNKNOWN : + markAsDefinitelyUnknown(local); + break; + case FlowInfo.NULL : + markAsDefinitelyNull(local); + break; + case FlowInfo.NON_NULL : + markAsDefinitelyNonNull(local); + break; + default: + // collect potential status: + resetNullInfo(local); + if ((nullStatus & FlowInfo.POTENTIALLY_UNKNOWN) != 0) + markPotentiallyUnknownBit(local); + if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) + markPotentiallyNullBit(local); + if ((nullStatus & FlowInfo.POTENTIALLY_NON_NULL) != 0) + markPotentiallyNonNullBit(local); + if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL|FlowInfo.POTENTIALLY_UNKNOWN)) == 0) + markAsDefinitelyUnknown(local); + } +} + +/** + * Answer the null status of the given local + * @param local + * @return bitset of FlowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL + */ +public int nullStatus(LocalVariableBinding local) { + if (isDefinitelyUnknown(local)) + return FlowInfo.UNKNOWN; + if (isDefinitelyNull(local)) + return FlowInfo.NULL; + if (isDefinitelyNonNull(local)) + return FlowInfo.NON_NULL; + int status = 0; + if (isPotentiallyUnknown(local)) + status |= FlowInfo.POTENTIALLY_UNKNOWN; + if (isPotentiallyNull(local)) + status |= FlowInfo.POTENTIALLY_NULL; + if (isPotentiallyNonNull(local)) + status |= FlowInfo.POTENTIALLY_NON_NULL; + if (status > 0) + return status; + return FlowInfo.UNKNOWN; +} + +/** * Merge branches using optimized boolean conditions */ public static UnconditionalFlowInfo mergedOptimizedBranches( 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.67 diff -u -r1.67 UnconditionalFlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 31 Aug 2010 14:58:05 -0000 1.67 +++ compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 9 Sep 2010 15:34:35 -0000 @@ -24,10 +24,8 @@ * No caching of pre-allocated instances. */ public class UnconditionalFlowInfo extends FlowInfo { - // Coverage tests /** - * Exception raised when unexpected behavior is detected during coverage - * tests. + * Exception raised when unexpected behavior is detected. */ public static class AssertionFailedException extends RuntimeException { private static final long serialVersionUID = 1827352841030089703L; @@ -976,7 +974,20 @@ & (this.extra[4][vectorIndex] ^ this.extra[5][vectorIndex]) & (1L << (position % BitCacheSize))) != 0; } - +/** Asserts that the given boolean is true. If this + * is not the case, some kind of unchecked exception is thrown. + * The given message is included in that exception, to aid debugging. + * + * @param expression the outcome of the check + * @param message the message to include in the exception + * @return true if the check passes (does not return + * if the check fails) + */ +private static boolean isTrue(boolean expression, String message) { + if (!expression) + throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$ + return expression; +} public void markAsComparedEqualToNonNull(LocalVariableBinding local) { // protected from non-object locals in calling methods if (this != DEAD_END) { @@ -1330,17 +1341,74 @@ } } -public void markAsPotentiallyNull(LocalVariableBinding local) { +public void resetNullInfo(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; + 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) { + // 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) { // use bits - this.nullBit1 &= ~(mask = 1L << position); + mask = 1L << position; + isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ + this.nullBit4 |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 46) { + this.nullBit4 = ~0; + } + } + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + mask = 1L << (position % BitCacheSize); + isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ + this.extra[5][vectorIndex] |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 47) { + this.extra[5][vectorIndex] = ~0; + } + } + } + } +} + +public void markPotentiallyNullBit(LocalVariableBinding local) { + if (this != DEAD_END) { + this.tagBits |= NULL_FLAG_MASK; + int position; + long mask; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + // use bits + mask = 1L << position; + isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ this.nullBit2 |= mask; - this.nullBit3 &= ~mask; - this.nullBit4 &= ~mask; if (COVERAGE_TEST_FLAG) { if(CoverageTestId == 40) { this.nullBit4 = ~0; @@ -1348,12 +1416,10 @@ } } else { // use extra vector - int vectorIndex ; - this.extra[2][vectorIndex = (position / BitCacheSize) - 1] - &= ~(mask = 1L << (position % BitCacheSize)); + int vectorIndex = (position / BitCacheSize) - 1; + mask = 1L << (position % BitCacheSize); this.extra[3][vectorIndex] |= mask; - this.extra[4][vectorIndex] &= (mask = ~mask); - this.extra[5][vectorIndex] &= mask; + isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ if (COVERAGE_TEST_FLAG) { if(CoverageTestId == 41) { this.extra[5][vectorIndex] = ~0; @@ -1363,6 +1429,36 @@ } } +public void markPotentiallyNonNullBit(LocalVariableBinding local) { + if (this != DEAD_END) { + this.tagBits |= NULL_FLAG_MASK; + int position; + long mask; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + // use bits + mask = 1L << position; + isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ + this.nullBit3 |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 42) { + this.nullBit4 = ~0; + } + } + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + mask = 1L << (position % BitCacheSize); + isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ + this.extra[4][vectorIndex] |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 43) { + this.extra[5][vectorIndex] = ~0; + } + } + } + } +} + public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) { if ((otherInits.tagBits & UNREACHABLE) != 0 && this != DEAD_END) { if (COVERAGE_TEST_FLAG) { #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.11 diff -u -r1.11 NullReferenceImplTests.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java 31 Aug 2010 14:58:00 -0000 1.11 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java 9 Sep 2010 15:34:39 -0000 @@ -559,11 +559,6 @@ assertTrue("nb of failures: " + failures, failures == 0); } -public void test2058_markAsPotentiallyNull() { - int failures = NullReferenceImplTransformations.markAsPotentiallyNull.test(); - assertTrue("nb of failures: " + failures, failures == 0); -} - public void test2060_addInitializationsFrom() { int failures = NullReferenceImplTransformations.addInitializationsFrom.test(); assertTrue("nb of failures: " + failures, failures == 0); @@ -875,7 +870,6 @@ test2055_markAsDefinitelyNonNull(); test2056_markAsDefinitelyNull(); test2057_markAsDefinitelyUnknown(); - test2058_markAsPotentiallyNull(); test2060_addInitializationsFrom(); test2061_addPotentialInitializationsFrom(); test2062_mergedWith(); @@ -897,7 +891,6 @@ test2055_markAsDefinitelyNonNull(); test2056_markAsDefinitelyNull(); test2057_markAsDefinitelyUnknown(); - test2058_markAsPotentiallyNull(); test2060_addInitializationsFrom(); test2061_addPotentialInitializationsFrom(); test2062_mergedWith(); @@ -1105,11 +1098,6 @@ super.markAsDefinitelyUnknown(local); } -public void markAsPotentiallyNull(LocalVariableBinding local) { - grow(local.id + this.maxFieldCount); - super.markAsPotentiallyNull(local); -} - /** * Return a fake unconditional flow info which bit fields represent the given * null bits for a local variable of id 0 within a class that would have no Index: src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTransformations.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTransformations.java,v retrieving revision 1.6 diff -u -r1.6 NullReferenceImplTransformations.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTransformations.java 31 Aug 2010 14:58:00 -0000 1.6 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTransformations.java 9 Sep 2010 15:34:39 -0000 @@ -242,50 +242,6 @@ return result; } }, - markAsPotentiallyNull = - // markAsDefinitelyNull DEFINITION START - // start => pot. null - // prot. non null => pot. null - // prot. null => pot. null - // pot. unknown => pot. null - // pot. non null => pot. null - // pot. nn & prot. nn => pot. null - // pot. nn & pot. un => pot. null - // pot. null => pot. null - // pot. n & prot. n => pot. null - // pot. n & pot. un => pot. null - // pot. n & pot. nn => pot. null - // def. unknown => pot. null - // def. non null => pot. null - // def. null => pot. null - // markAsPotentiallyNull DEFINITION END - // PREMATURE add 'catch rules' - new TwoDimensionalTransformation("markAsPotentiallyNull", - new byte[][] { - // markAsPotentiallyNull INITIALIZER START - {0x00,0x08}, - {0x04,0x08}, - {0x08,0x08}, - {0x0C,0x08}, - {0x10,0x08}, - {0x14,0x08}, - {0x18,0x08}, - {0x24,0x08}, - {0x28,0x08}, - {0x2C,0x08}, - {0x30,0x08}, - {0x34,0x08}, - {0x38,0x08}, - {0x3C,0x08}, - // markAsPotentiallyNull INITIALIZER END - }) { - UnconditionalFlowInfo output(UnconditionalFlowInfo input, - TestLocalVariableBinding local) { - UnconditionalFlowInfo result = (UnconditionalFlowInfo)input.copy(); - result.markAsPotentiallyNull(local); - return result; - } - }, addInitializationsFrom = // addInitializationsFrom DEFINITION START // def. non null + def. non null => def. non null 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.101 diff -u -r1.101 NullReferenceTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 1 Sep 2010 15:43:25 -0000 1.101 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 9 Sep 2010 15:34:40 -0000 @@ -35,7 +35,7 @@ // Only the highest compliance level is run; add the VM argument // -Dcompliance=1.4 (for example) to lower it if needed static { -// TESTS_NAMES = new String[] { "testBug320414" }; +// TESTS_NAMES = new String[] { "testBug292478g" }; // TESTS_NUMBERS = new int[] { 561 }; // TESTS_RANGE = new int[] { 1, 2049 }; } @@ -13222,4 +13222,132 @@ "Potential null pointer access: The variable y may be null at this location\n" + "----------\n"); } + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +// test regression reported in comment 8 +public void testBug292478e() { + this.runConformTest( + new String[] { + "Test.java", + "public class Test {\n" + + " Object foo(int i, boolean b1, boolean b2) {\n" + + " Object o1 = null;\n" + + " done : while (true) { \n" + + " switch (i) {\n" + + " case 1 :\n" + + " Object o2 = null;\n" + + " if (b2)\n" + + " o2 = new Object();\n" + + " o1 = o2;\n" + + " break;\n" + + " case 2 :\n" + + " break done;\n" + + " }\n" + + " } \n" + + " if (o1 != null)\n" + + " return o1;\n" + + " return null;\n" + + " }\n" + + "}\n" + }); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +// variant where regression occurred inside the while-switch structure +public void testBug292478f() { + this.runConformTest( + new String[] { + "Test.java", + "public class Test {\n" + + " Object foo(int i, boolean b1, boolean b2) {\n" + + " Object o1 = null;\n" + + " done : while (true) { \n" + + " switch (i) {\n" + + " case 1 :\n" + + " Object o2 = null;\n" + + " if (b2)\n" + + " o2 = new Object();\n" + + " o1 = o2;\n" + + " if (o1 != null)\n" + + " return o1;\n" + + " break;\n" + + " case 2 :\n" + + " break done;\n" + + " }\n" + + " } \n" + + " return null;\n" + + " }\n" + + "}\n" + }); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 - Report potentially null across variable assignment +// variant for transfering state potentially unknown +public void testBug292478g() { + this.runConformTest( + new String[] { + "Test.java", + "public class Test {\n" + + " Object foo(int i, boolean b1, boolean b2, Object o2) {\n" + + " Object o1 = null;\n" + + " done : while (true) { \n" + + " switch (i) {\n" + + " case 1 :\n" + + " if (b2)\n" + + " o2 = bar();\n" + + " o1 = o2;\n" + + " if (o1 != null)\n" + + " return o1;\n" + + " break;\n" + + " case 2 :\n" + + " break done;\n" + + " }\n" + + " } \n" + + " return null;\n" + + " }\n" + + " Object bar() { return null; }\n" + + "}\n" + }); +} + +// Bug 324762 - Compiler thinks there is deadcode and removes it! +// regression caused by the fix for bug 133125 +// ternary is non-null or null +public void testBug324762() { + this.runConformTest( + new String[] { + "Test.java", + "public class Test {\n" + + " void zork(boolean b1) {\n" + + " Object satisfied = null;\n" + + " if (b1) {\n" + + " String[] s = new String[] { \"a\", \"b\" };\n" + + " for (int k = 0; k < s.length && satisfied == null; k++)\n" + + " satisfied = s.length > 1 ? new Object() : null;\n" + + " }\n" + + " }\n" + + "}\n" + }); +} + +// Bug 324762 - Compiler thinks there is deadcode and removes it! +// regression caused by the fix for bug 133125 +// ternary is unknown or null +public void testBug324762a() { + this.runConformTest( + new String[] { + "Test.java", + "public class Test {\n" + + " void zork(boolean b1) {\n" + + " Object satisfied = null;\n" + + " if (b1) {\n" + + " String[] s = new String[] { \"a\", \"b\" };\n" + + " for (int k = 0; k < s.length && satisfied == null; k++)\n" + + " satisfied = s.length > 1 ? bar() : null;\n" + + " }\n" + + " }\n" + + " Object bar() { return null; }\n" + + "}\n" + }); +} } \ No newline at end of file