Index: compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java,v --- compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java 7 Mar 2009 00:59:06 -0000 1.61 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java 15 Jan 2010 06:38:10 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2010 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 @@ -556,12 +556,27 @@ case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: case CAN_ONLY_NULL | IN_ASSIGNMENT: case CAN_ONLY_NULL | IN_INSTANCEOF: + TypeBinding compileTimeType = reference.resolvedType; if (flowInfo.isDefinitelyNull(local)) { switch(checkType & CONTEXT_MASK) { case FlowContext.IN_COMPARISON_NULL: + if (!compileTimeType.isBaseType() && ((checkType & CHECK_MASK) == CAN_ONLY_NULL)) { // check for auto-unboxing first and report appropriate warning + TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType); + if (unboxedType != null && unboxedType != compileTimeType) { + scope.problemReporter().localVariableNullReference(local, reference); + return; + } + } scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); return; case FlowContext.IN_COMPARISON_NON_NULL: + if (!compileTimeType.isBaseType() && ((checkType & CHECK_MASK) == CAN_ONLY_NULL)) { // check for auto-unboxing first and report appropriate warning + TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType); + if (unboxedType != null && unboxedType != compileTimeType) { + scope.problemReporter().localVariableNullReference(local, reference); + return; + } + } scope.problemReporter().localVariableNullComparedToNonNull(local, reference); return; case FlowContext.IN_ASSIGNMENT: @@ -571,6 +586,27 @@ scope.problemReporter().localVariableNullInstanceof(local, reference); return; } + } else if (flowInfo.isPotentiallyNull(local)) { + switch(checkType & CONTEXT_MASK) { + case FlowContext.IN_COMPARISON_NULL: + if (!compileTimeType.isBaseType() && ((checkType & CHECK_MASK) == CAN_ONLY_NULL)) { // check for auto-unboxing first and report appropriate warning + TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType); + if (unboxedType != null && unboxedType != compileTimeType) { + scope.problemReporter().localVariablePotentialNullReference(local, reference); + return; + } + } + break; + case FlowContext.IN_COMPARISON_NON_NULL: + if (!compileTimeType.isBaseType() && ((checkType & CHECK_MASK) == CAN_ONLY_NULL)) { // check for auto-unboxing first and report appropriate warning + TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType); + if (unboxedType != null && unboxedType != compileTimeType) { + scope.problemReporter().localVariablePotentialNullReference(local, reference); + return; + } + } + break; + } } else if (flowInfo.cannotBeDefinitelyNullOrNonNull(local)) { return; } 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 --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 19 Nov 2009 15:57:22 -0000 1.83 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 15 Jan 2010 06:38:17 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2009 IBM Corporation and others. + * Copyright (c) 2005, 2010 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 @@ -12,9 +12,10 @@ import java.util.Map; +import junit.framework.Test; + import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import junit.framework.Test; /* See also NullReferenceImplTests for low level, implementation dependent * tests. */ @@ -10328,4 +10329,81 @@ "----------\n"); } } + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=253896 +// Test whether Null pointer access warnings are being reported correctly when auto-unboxing +public void testBug253896a() { + if (this.complianceLevel >= ClassFileConstants.JDK1_5) { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public void foo() {\n" + + " Integer f1 = null;\n" + + " if(f1 == 1)\n" + + " System.out.println(\"f1 is 1\");\n" + + " Integer f2 = null;\n" + + " int abc = (f2 != 1)? 1 : 0;\n" + + " Float f3 = null;\n" + + " if(f3 == null)\n" + + " System.out.println(\"i1 is null\");\n" + + " Byte f4 = null;\n" + + " if(f4 != null)\n" + + " System.out.println(\"i2 is not null\");\n" + + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 4)\n" + + " if(f1 == 1)\n" + + " ^^\n" + + "Null pointer access: The variable f1 can only be null at this location\n" + + "----------\n" + + "2. ERROR in X.java (at line 7)\n" + + " int abc = (f2 != 1)? 1 : 0;\n" + + " ^^\n" + + "Null pointer access: The variable f2 can only be null at this location\n" + + "----------\n" + + "3. ERROR in X.java (at line 9)\n" + + " if(f3 == null)\n" + + " ^^\n" + + "Redundant null check: The variable f3 can only be null at this location\n" + + "----------\n" + + "4. ERROR in X.java (at line 12)\n" + + " if(f4 != null)\n" + + " ^^\n" + + "Null comparison always yields false: The variable f4 can only be null at this location\n" + + "----------\n"); + } +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=253896 +// To test whether null pointer access and potential null pointer access warnings are correctly reported when auto-unboxing +public void testBug253896b() { + if (this.complianceLevel >= ClassFileConstants.JDK1_5) { + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public void foo(Integer i1, Integer i2) {\n" + + " if(i1 == null && i2 == null){\n" + + " if(i1 == 1)\n" + + " System.out.println(i1);}\n" + //i1 is definitely null here + " else {\n" + + " if(i1 == 0) {}\n" + //i1 may be null here. + " }\n" + + " }\n" + + "}"}, + "----------\n" + + "1. ERROR in X.java (at line 4)\n" + + " if(i1 == 1)\n" + + " ^^\n" + + "Null pointer access: The variable i1 can only be null at this location\n" + + "----------\n" + + "2. ERROR in X.java (at line 7)\n" + + " if(i1 == 0) {}\n" + + " ^^\n" + + "Potential null pointer access: The variable i1 may be null at this location\n" + + "----------\n"); + } +} }