### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/core/compiler/IProblem.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java,v retrieving revision 1.225 diff -u -r1.225 IProblem.java --- compiler/org/eclipse/jdt/core/compiler/IProblem.java 16 Jan 2011 22:43:21 -0000 1.225 +++ compiler/org/eclipse/jdt/core/compiler/IProblem.java 1 Feb 2011 05:32:30 -0000 @@ -1245,6 +1245,26 @@ /** @since 3.4 */ int UnusedTypeArgumentsForConstructorInvocation = MethodRelated + 660; + /** + * Null analysis for fields + */ + /** @since 3.7 */ + int NullFieldReference = Internal + FieldRelated + 670; + /** @since 3.7 */ + int PotentialNullFieldReference = Internal + FieldRelated + 671; + /** @since 3.7 */ + int RedundantNullCheckOnNullField = Internal + FieldRelated + 672; + /** @since 3.7 */ + int NullFieldComparisonYieldsFalse = Internal + FieldRelated + 673; + /** @since 3.7 */ + int RedundantNullCheckOnNonNullField = Internal + FieldRelated + 674; + /** @since 3.7 */ + int NonNullFieldComparisonYieldsFalse = Internal + FieldRelated + 675; + /** @since 3.7 */ + int RedundantFieldNullAssignment = Internal + FieldRelated + 676; + /** @since 3.7 */ + int NullFieldInstanceofYieldsFalse = Internal + FieldRelated + 677; + /** * Corrupted binaries */ 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.95 diff -u -r1.95 Assignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 22 Jan 2011 23:39:25 -0000 1.95 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 1 Feb 2011 05:32:30 -0000 @@ -40,7 +40,7 @@ // 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 local = this.lhs.variableBinding(); if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { this.expression.checkNPE(currentScope, flowContext, flowInfo); } @@ -59,6 +59,12 @@ flowInfo.markNullStatus(local, nullStatus); if (flowContext.initsOnFinally != null) flowContext.initsOnFinally.markNullStatus(local, nullStatus); + if (local instanceof FieldBinding && local.isFinal() && ((FieldBinding) local).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) local; + fieldBinding.setNullStatusForStaticFinalField(nullStatus); + } } return flowInfo; } @@ -208,4 +214,7 @@ public LocalVariableBinding localVariableBinding() { return this.lhs.localVariableBinding(); } +public VariableBinding variableBinding() { + return this.lhs.variableBinding(); +} } Index: compiler/org/eclipse/jdt/internal/compiler/ast/Block.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java,v retrieving revision 1.43 diff -u -r1.43 Block.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Block.java 14 Oct 2009 18:08:37 -0000 1.43 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Block.java 1 Feb 2011 05:32:30 -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 @@ -36,6 +36,8 @@ flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo); } } + // don't let the flow info collected for fields from this block persist. + flowInfo.resetNullInfoForFields(); return flowInfo; } /** Index: compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java,v retrieving revision 1.137 diff -u -r1.137 CastExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java 17 Dec 2010 06:40:12 -0000 1.137 +++ compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java 1 Feb 2011 05:32:30 -0000 @@ -32,6 +32,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 { @@ -444,6 +445,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); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java,v retrieving revision 1.81 diff -u -r1.81 EqualExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java 15 Sep 2010 16:10:50 -0000 1.81 +++ compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java 1 Feb 2011 05:32:30 -0000 @@ -24,23 +24,23 @@ } private void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) { - 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); 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.133 diff -u -r1.133 Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 17 Jan 2011 08:05:01 -0000 1.133 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 1 Feb 2011 05:32:30 -0000 @@ -35,6 +35,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; @@ -506,14 +507,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); @@ -849,7 +850,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; @@ -1055,4 +1056,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; +} } Index: compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java,v retrieving revision 1.102 diff -u -r1.102 FieldDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java 5 Jan 2011 19:57:26 -0000 1.102 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java 1 Feb 2011 05:32:30 -0000 @@ -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; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java,v retrieving revision 1.131 diff -u -r1.131 FieldReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 17 Dec 2010 09:38:55 -0000 1.131 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 1 Feb 2011 05:32:30 -0000 @@ -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 @@ -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,18 @@ } 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(); +} + } Index: compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java,v retrieving revision 1.62 diff -u -r1.62 InstanceOfExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java 15 Sep 2010 16:10:51 -0000 1.62 +++ compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java 1 Feb 2011 05:32:30 -0000 @@ -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()); Index: compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java,v retrieving revision 1.151 diff -u -r1.151 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 16 Jan 2011 22:43:21 -0000 1.151 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 1 Feb 2011 05:32:30 -0000 @@ -95,6 +95,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; } /** 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.129 diff -u -r1.129 SingleNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 17 Dec 2010 09:38:55 -0000 1.129 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 1 Feb 2011 05:32:30 -0000 @@ -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 } Index: compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java,v retrieving revision 1.51 diff -u -r1.51 Statement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java 22 Jan 2011 23:39:25 -0000 1.51 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java 1 Feb 2011 05:32:30 -0000 @@ -56,7 +56,7 @@ public static final int COMPLAINED_UNREACHABLE = 2; /** Empty hook for checking null status against declaration using null annotations, once this will be supported. */ -protected int checkAgainstNullAnnotation(BlockScope currentScope, LocalVariableBinding local, int nullStatus) { +protected int checkAgainstNullAnnotation(BlockScope currentScope, VariableBinding local, int nullStatus) { return nullStatus; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java,v retrieving revision 1.165 diff -u -r1.165 TypeDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java 5 Jan 2011 19:57:26 -0000 1.165 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java 1 Feb 2011 05:32:30 -0000 @@ -43,6 +43,7 @@ public MethodScope staticInitializerScope; public boolean ignoreFurtherInvestigation = false; public int maxFieldCount; +// public int maxFieldCountForFlowInfo; // cumulative count of fields in this type and enclosing types public int declarationSourceStart; public int declarationSourceEnd; public int bodyStart; @@ -59,6 +60,7 @@ // 1.5 support public TypeParameter[] typeParameters; + private int maxFieldCountForFlowInfo; public TypeDeclaration(CompilationResult compilationResult){ this.compilationResult = compilationResult; @@ -198,8 +200,27 @@ localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); } manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + + + +// if (this.enclosingType != null) { +// this.maxFieldCountForFlowInfo = this.enclosingType.maxFieldCountForFlowInfo + this.maxFieldCount; +// } else { +// this.maxFieldCountForFlowInfo = this.maxFieldCount; +// } updateMaxFieldCount(); // propagate down the max field count - internalAnalyseCode(flowContext, flowInfo); + +// if ((this.binding.tagBits & ASTNode.IsLocalType) != 0) { +// // non-anonymous local type can declare its fields. So change the cumulativeFieldCount +// UnconditionalFlowInfo unconFlowInfo = flowInfo.unconditionalInits(); +// int tempCount = unconFlowInfo.maxFieldCount; +// unconFlowInfo.maxFieldCount = this.scope.cumulativeFieldCount; +// internalAnalyseCode(flowContext, flowInfo); +// unconFlowInfo.maxFieldCount = tempCount; +// } else { + + internalAnalyseCode(flowContext, flowInfo); +// } } catch (AbortType e) { this.ignoreFurtherInvestigation = true; } @@ -214,6 +235,13 @@ if (this.ignoreFurtherInvestigation) return; try { + + +// if (this.enclosingType == null) { +// this.maxFieldCountForFlowInfo = this.maxFieldCount; +// } else { +// this.maxFieldCountForFlowInfo = this.enclosingType.maxFieldCountForFlowInfo + this.maxFieldCount; +// } // propagate down the max field count updateMaxFieldCount(); internalAnalyseCode(null, FlowInfo.initial(this.maxFieldCount)); @@ -236,8 +264,22 @@ localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); } manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); + + + +// if (this.enclosingType == null) { +// this.maxFieldCountForFlowInfo = this.maxFieldCount; +// } else { +// this.maxFieldCountForFlowInfo = this.enclosingType.maxFieldCountForFlowInfo + this.maxFieldCount; +// } updateMaxFieldCount(); // propagate down the max field count + //flowInfo.unconditionalInits().maxFieldCount = this.maxFieldCountForFlowInfo; + UnconditionalFlowInfo unconFlowInfo = flowInfo.unconditionalInits(); + //int tempCount = unconFlowInfo.maxFieldCount; + //unconFlowInfo.maxFieldCount = this.scope.cumulativeFieldCount; internalAnalyseCode(flowContext, flowInfo); + //flowInfo.resetNullInfoForFields(); + //unconFlowInfo.maxFieldCount = tempCount; } catch (AbortType e) { this.ignoreFurtherInvestigation = true; } @@ -251,6 +293,11 @@ if (this.ignoreFurtherInvestigation) return; try { +// if (this.enclosingType == null) { +// this.maxFieldCountForFlowInfo = this.maxFieldCount; +// } else { +// this.maxFieldCountForFlowInfo = this.enclosingType.maxFieldCountForFlowInfo + this.maxFieldCount; +// } internalAnalyseCode(null, FlowInfo.initial(this.maxFieldCount)); } catch (AbortType e) { this.ignoreFurtherInvestigation = true; @@ -646,7 +693,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); + staticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE); } } else { if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE) != 0) @@ -662,7 +709,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); + nonStaticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE); } } } @@ -678,7 +725,10 @@ } if (this.methods != null) { UnconditionalFlowInfo outerInfo = flowInfo.unconditionalFieldLessCopy(); - FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo); + boolean isLocal = (this.binding.tagBits & ASTNode.IsLocalType) != 0; + //int fieldOffset = isLocal ? this.scope.cumulativeFieldCount : this.maxFieldCount; + //int fieldStart = isLocal ? this.scope.localTypeFieldIdStart : 0; + FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations(0).addInitializationsFrom(outerInfo); for (int i = 0, count = this.methods.length; i < count; i++) { AbstractMethodDeclaration method = this.methods[i]; if (method.ignoreFurtherInvestigation) @@ -688,7 +738,7 @@ method.analyseCode( this.scope, staticInitializerContext, - staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo)); + staticFieldInfo.unconditionalInits().discardNonFieldInitializations(0).addInitializationsFrom(outerInfo)); } else { // constructor ((ConstructorDeclaration)method).analyseCode(this.scope, initializerContext, constructorInfo.copy(), flowInfo.reachMode()); } @@ -1042,11 +1092,23 @@ 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]; @@ -1067,6 +1129,7 @@ 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) @@ -1084,9 +1147,25 @@ 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 (this.memberTypes != null) { +// for (int i = 0, count = this.memberTypes.length; i < count; i++) { +// this.memberTypes[i].maxFieldCount += this.maxFieldCount; +// } +// } + +// if (this.enclosingType != null) +// this.maxFieldCount += this.enclosingType.maxFieldCount; + if (needSerialVersion) { //check that the current type doesn't extend javax.rmi.CORBA.Stub TypeBinding javaxRmiCorbaStub = this.scope.getType(TypeConstants.JAVAX_RMI_CORBA_STUB, 4); @@ -1173,6 +1252,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 */ @@ -1449,8 +1539,30 @@ } else { this.maxFieldCount = outerMostType.maxFieldCount; // down } + } +//int getMaxFieldCountForFlowInfo() { +// int maxFieldCountForFlowInfo = 0; +// if (this.binding == null) +// return maxFieldCountForFlowInfo; // error scenario +// ReferenceBinding superClassBinding = this.binding.superclass; +// while (superClassBinding != null) { +// FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields(); +// if (unResolvedFields != null) { +// this.maxFieldCount += unResolvedFields.length; +// } +// superClassBinding = superClassBinding.superclass(); +// } +// ReferenceBinding[] superInterfacesBinding = this.binding.superInterfaces; +// maxFieldCountForFlowInfo += findFieldCountFromSuperInterfaces(superInterfacesBinding); +// if (this.enclosingType != null) { +// maxFieldCountForFlowInfo += this.enclosingType.maxFieldCount; +// } +// return maxFieldCountForFlowInfo; +// +//} + /** * Returns whether the type is a secondary one or not. */ 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.33 diff -u -r1.33 ConditionalFlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java 16 Dec 2010 13:02:30 -0000 1.33 +++ compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java 1 Feb 2011 05:32:30 -0000 @@ -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)); } 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.35 diff -u -r1.35 FinallyFlowContext.java --- compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java 25 Feb 2010 15:27:00 -0000 1.35 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java 1 Feb 2011 05:32:30 -0000 @@ -30,7 +30,7 @@ VariableBinding[] finalVariables; int assignCount; - LocalVariableBinding[] nullLocals; + VariableBinding[] nullVariables; Expression[] nullReferences; int[] nullCheckTypes; int nullCount; @@ -83,7 +83,7 @@ // check inconsistent null checks if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) { // within an enclosing loop, be conservative for (int i = 0; i < this.nullCount; i++) { - this.parent.recordUsingNullReference(scope, this.nullLocals[i], + this.parent.recordUsingNullReference(scope, this.nullVariables[i], this.nullReferences[i], this.nullCheckTypes[i], flowInfo); } } @@ -91,18 +91,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; @@ -116,27 +116,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)) { @@ -144,14 +144,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; @@ -160,11 +160,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; default: @@ -212,7 +212,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 @@ -226,14 +226,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); } } 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); @@ -245,11 +245,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); @@ -257,34 +257,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); } 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; @@ -296,7 +296,7 @@ return; } if (flowInfo.canOnlyBeNull(local)) { - scope.problemReporter().localVariableNullReference(local, reference); + scope.problemReporter().variableNullReference(local, reference); return; } break; @@ -311,14 +311,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); } } 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); @@ -335,11 +335,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); @@ -347,34 +347,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); } 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; @@ -383,11 +383,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)) { @@ -419,17 +419,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, @@ -438,7 +438,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; } 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 retrieving revision 1.68 diff -u -r1.68 FlowContext.java --- compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java 1 Sep 2010 15:49:57 -0000 1.68 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java 1 Feb 2011 05:32:30 -0000 @@ -23,7 +23,6 @@ import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; @@ -520,7 +519,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 } @@ -563,7 +562,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)) { @@ -575,14 +574,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); } } 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); @@ -602,11 +601,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); @@ -614,34 +613,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); } 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; @@ -652,11 +651,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; 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.45 diff -u -r1.45 FlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 16 Dec 2010 13:02:30 -0000 1.45 +++ compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java 1 Feb 2011 05:32:30 -0000 @@ -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 { @@ -79,39 +80,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); } /** @@ -159,25 +163,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. @@ -191,59 +199,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. @@ -251,34 +259,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. @@ -286,59 +298,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; @@ -555,12 +567,12 @@ * 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); } Index: compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java,v retrieving revision 1.51 diff -u -r1.51 LoopingFlowContext.java --- compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java 23 Aug 2010 08:41:25 -0000 1.51 +++ compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java 1 Feb 2011 05:32:30 -0000 @@ -42,7 +42,7 @@ VariableBinding finalVariables[]; int assignCount = 0; - LocalVariableBinding[] nullLocals; + VariableBinding[] nullVariables; Expression[] nullReferences; int[] nullCheckTypes; int nullCount; @@ -138,7 +138,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]) { @@ -148,11 +148,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; @@ -164,11 +164,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; @@ -177,11 +177,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; @@ -196,27 +196,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)) { @@ -224,14 +224,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; @@ -241,7 +241,7 @@ case MAY_NULL: if (flowInfo.isDefinitelyNull(local)) { this.nullReferences[i] = null; - scope.problemReporter().localVariableNullReference(local, expression); + scope.problemReporter().variableNullReference(local, expression); continue; } break; @@ -257,7 +257,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: @@ -265,11 +265,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; @@ -284,27 +284,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)) { @@ -312,14 +312,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; @@ -329,12 +329,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; @@ -458,27 +458,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)) { @@ -490,14 +490,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); } } 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); @@ -506,21 +506,21 @@ } 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); } } 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); } } } else if (this.upstreamNullFlowInfo.isDefinitelyNonNull(local) && !flowInfo.isPotentiallyNull(local)) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=291418 - flowInfo.markAsDefinitelyNonNull(local); + flowInfo.markAsDefinitelyNonNull(local ); if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) { recordNullReference(local, reference, checkType); } @@ -546,11 +546,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); @@ -558,34 +558,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); } 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; @@ -604,11 +604,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); Index: compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java,v retrieving revision 1.12 diff -u -r1.12 NullInfoRegistry.java --- compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java 19 Jan 2011 05:29:54 -0000 1.12 +++ compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java 1 Feb 2011 05:32:30 -0000 @@ -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$ 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.72 diff -u -r1.72 UnconditionalFlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 19 Jan 2011 05:29:54 -0000 1.72 +++ compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 1 Feb 2011 05:32:30 -0000 @@ -18,6 +18,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 @@ -515,13 +516,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 @@ -546,13 +552,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) @@ -573,13 +584,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) @@ -664,10 +680,11 @@ * Remove local variables information from this flow info and return this. * @return this, deprived from any local variable information */ -public UnconditionalFlowInfo discardNonFieldInitializations() { +public UnconditionalFlowInfo discardNonFieldInitializations(int fieldStart) { int limit = this.maxFieldCount; if (limit < BitCacheSize) { long mask = (1L << limit)-1; + //mask = mask & (-1L << fieldStart); this.definiteInits &= mask; this.potentialInits &= mask; this.nullBit1 &= mask; @@ -745,7 +762,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) { @@ -755,7 +778,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; @@ -774,14 +806,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)) @@ -801,13 +848,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; @@ -860,13 +912,18 @@ return isPotentiallyAssigned(local.id + this.maxFieldCount); } -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; @@ -885,13 +942,22 @@ & (1L << (position % BitCacheSize))) != 0; } -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; @@ -910,13 +976,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) @@ -937,14 +1008,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 @@ -962,13 +1037,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) @@ -1001,15 +1081,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) @@ -1098,14 +1184,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 @@ -1236,14 +1328,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; + if (local instanceof FieldBinding) { + this.markNullStatus(local, FlowInfo.POTENTIALLY_NON_NULL); + return; + } 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 non null this.nullBit1 |= (mask = 1L << position); this.nullBit3 |= mask; @@ -1258,8 +1356,25 @@ } else { // use extra vector - int vectorIndex ; - this.extra[2][vectorIndex = (position / BitCacheSize) - 1] + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 0; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } + else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[0].length)) { + for (int j = 0; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } + this.extra[2][vectorIndex] |= (mask = 1L << (position % BitCacheSize)); this.extra[4][vectorIndex] |= mask; this.extra[3][vectorIndex] &= (mask = ~mask); @@ -1273,14 +1388,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; + if (local instanceof FieldBinding) { + this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL); + return; + } else { + position = local.id + this.maxFieldCount; + } // position is zero-based - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits + if (position < BitCacheSize) { // use bits // mark assigned null this.nullBit1 |= (mask = 1L << position); this.nullBit2 |= mask; @@ -1295,8 +1416,25 @@ } else { // use extra vector - int vectorIndex ; - this.extra[2][vectorIndex = (position / BitCacheSize) - 1] + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 0; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } + else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[0].length)) { + for (int j = 0; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } + this.extra[2][vectorIndex] |= (mask = 1L << (position % BitCacheSize)); this.extra[3][vectorIndex] |= mask; this.extra[4][vectorIndex] &= (mask = ~mask); @@ -1316,14 +1454,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; + if (local instanceof FieldBinding) { + position = local.id; + } else { + position = local.id + this.maxFieldCount; + } // position is zero-based - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + if (position < BitCacheSize) { // use bits // mark assigned null this.nullBit1 |= (mask = 1L << position); @@ -1339,8 +1482,25 @@ } else { // use extra vector - int vectorIndex ; - this.extra[2][vectorIndex = (position / BitCacheSize) - 1] + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 0; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } + else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[0].length)) { + for (int j = 0; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } + this.extra[2][vectorIndex] |= (mask = 1L << (position % BitCacheSize)); this.extra[5][vectorIndex] |= mask; this.extra[3][vectorIndex] &= (mask = ~mask); @@ -1354,12 +1514,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; @@ -1381,18 +1546,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$ @@ -1434,12 +1635,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$ @@ -1481,12 +1687,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$ @@ -2007,8 +2218,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]; @@ -2021,8 +2237,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; } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java,v retrieving revision 1.123 diff -u -r1.123 BlockScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 17 Dec 2010 09:38:59 -0000 1.123 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 1 Feb 2011 05:32:30 -0000 @@ -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 @@ -97,6 +97,18 @@ // update local variable binding binding.declaringScope = this; binding.id = outerMostMethodScope().analysisIndex++; +// int cumulativeMaxFieldCounts = 0; + ClassScope outerClassScope = this.enclosingClassScope(); +// TypeDeclaration typeDeclaration = (outerClassScope != null)? outerClassScope.referenceType() : null; +// while (typeDeclaration != null) { +// cumulativeMaxFieldCounts += typeDeclaration.maxFieldCount; +// typeDeclaration = typeDeclaration.enclosingType; +// } + if (outerClassScope != null) { + //if (outerClassScope.referenceContext.binding != null && ((outerClassScope.referenceContext.binding.tagBits & ASTNode.IsLocalType) != 0)) + //binding.id += outerClassScope.cumulativeFieldCount; + } + // share the outermost method scope analysisIndex } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java,v retrieving revision 1.183 diff -u -r1.183 ClassScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java 1 Nov 2010 14:15:47 -0000 1.183 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java 1 Feb 2011 05:32:30 -0000 @@ -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 @@ -34,11 +34,14 @@ 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) { @@ -75,6 +78,8 @@ } } } + this.cumulativeFieldCount += outerMostMethodScope().analysisIndex; + this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex; connectMemberTypes(); buildFieldsAndMethods(); anonymousType.faultInTypesForFieldsAndMethods(); @@ -104,6 +109,24 @@ 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) { @@ -111,7 +134,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); @@ -139,6 +162,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); } @@ -218,6 +242,8 @@ checkParameterizedTypeBounds(); checkParameterizedSuperTypeCollisions(); } + this.cumulativeFieldCount += outerMostMethodScope().analysisIndex; + this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex; buildFieldsAndMethods(); localType.faultInTypesForFieldsAndMethods(); @@ -1251,4 +1277,15 @@ + this.referenceContext.binding.toString(); return "--- Class Scope ---\n\n Binding not initialized" ; //$NON-NLS-1$ } + + 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; + } } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java,v retrieving revision 1.60 diff -u -r1.60 FieldBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java 22 Oct 2010 22:42:56 -0000 1.60 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java 1 Feb 2011 05:32:30 -0000 @@ -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; +} } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java,v retrieving revision 1.140 diff -u -r1.140 ReferenceBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java 23 Dec 2010 13:57:49 -0000 1.140 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java 1 Feb 2011 05:32:30 -0000 @@ -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 @@ -38,6 +38,7 @@ char[] fileName; char[] constantPoolName; char[] signature; +// int cumulativeFieldCount; private SimpleLookupTable compatibleCache; @@ -1380,4 +1381,17 @@ public FieldBinding[] unResolvedFields() { return Binding.NO_FIELDS; } + +//public int findCumulativeFieldCount() { +// FieldBinding[] unResolvedFields = this.unResolvedFields(); +// if (unResolvedFields != null) { +// this.cumulativeFieldCount += unResolvedFields.length; +// } +// ReferenceBinding superClassBinding = this.superclass(); +// if (superClassBinding != null) { +// this.cumulativeFieldCount += superClassBinding.cumulativeFieldCount; +// } +// ReferenceBinding[] superInterfacesBinding = this.superInterfaces; +// return this.cumulativeFieldCount; +//} } Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v retrieving revision 1.430 diff -u -r1.430 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 16 Jan 2011 22:43:21 -0000 1.430 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 1 Feb 2011 05:32:30 -0000 @@ -103,6 +103,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; @@ -280,17 +281,25 @@ return CompilerOptions.VarargsArgumentNeedCast; case IProblem.NullLocalVariableReference: + case IProblem.NullFieldReference: return CompilerOptions.NullReference; case IProblem.PotentialNullLocalVariableReference: + case IProblem.PotentialNullFieldReference: 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.NullFieldInstanceofYieldsFalse: + case IProblem.RedundantNullCheckOnNonNullField: + case IProblem.RedundantNullCheckOnNullField: + case IProblem.NonNullFieldComparisonYieldsFalse: + case IProblem.NullFieldComparisonYieldsFalse: return CompilerOptions.RedundantNullCheck; case IProblem.BoxingConversion : @@ -4866,108 +4875,156 @@ } } -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) { - int severity = computeSeverity(IProblem.RedundantLocalVariableNullAssignment); +public void variableRedundantNullAssignment (VariableBinding variable, ASTNode location) { + 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) { Index: compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties,v retrieving revision 1.262 diff -u -r1.262 messages.properties --- compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 16 Jan 2011 22:43:21 -0000 1.262 +++ compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 1 Feb 2011 05:32:30 -0000 @@ -572,6 +572,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} Index: eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java,v retrieving revision 1.56 diff -u -r1.56 CodeSnippetClassFile.java --- eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java 7 Jan 2010 20:17:47 -0000 1.56 +++ eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java 1 Feb 2011 05:32:30 -0000 @@ -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 #P org.eclipse.jdt.core.tests Index: Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java =================================================================== RCS file: /home/cvs/numbat/org.eclipse.jdt.core.tests/Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java,v retrieving revision 1.130 diff -u -r1.130 InitializationTest.java --- Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java 10 Jan 2011 19:30:50 -0000 1.130 +++ Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java 1 Feb 2011 05:32:36 -0000 @@ -32,7 +32,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[] { "test011" }; + TESTS_NAMES = new String[] { "test001" }; // TESTS_NUMBERS = new int[] { 204 }; // TESTS_RANGE = new int[] { 231, 240 }; } #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java,v retrieving revision 1.40 diff -u -r1.40 CompilerInvocationTests.java --- src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java 16 Jan 2011 22:43:57 -0000 1.40 +++ src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java 1 Feb 2011 05:32:37 -0000 @@ -696,6 +696,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)); @@ -708,6 +709,9 @@ expectedProblemAttributes.put("NotVisibleField", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("NotVisibleMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("NotVisibleType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); + 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)); @@ -745,6 +749,7 @@ expectedProblemAttributes.put("ParsingErrorReplaceTokens", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); expectedProblemAttributes.put("ParsingErrorUnexpectedEOF", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); expectedProblemAttributes.put("PossibleAccidentalBooleanAssignment", 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("PublicClassMustMatchFileName", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("RawMemberTypeCannotBeParameterized", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); @@ -752,8 +757,11 @@ expectedProblemAttributes.put("RecursiveConstructorInvocation", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("RedefinedArgument", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("RedefinedLocal", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); + expectedProblemAttributes.put("RedundantFieldNullAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantLocalVariableNullAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); + 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("RedundantNullCheckOnNullLocalVariable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("RedundantSuperinterface", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE)); expectedProblemAttributes.put("ReferenceToForwardField", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); @@ -1333,6 +1341,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)); @@ -1345,6 +1354,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)); @@ -1382,6 +1394,7 @@ expectedProblemAttributes.put("ParsingErrorReplaceTokens", SKIP); expectedProblemAttributes.put("ParsingErrorUnexpectedEOF", SKIP); expectedProblemAttributes.put("PossibleAccidentalBooleanAssignment", new ProblemAttributes(JavaCore.COMPILER_PB_POSSIBLE_ACCIDENTAL_BOOLEAN_ASSIGNMENT)); + 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); @@ -1389,8 +1402,11 @@ expectedProblemAttributes.put("RecursiveConstructorInvocation", SKIP); expectedProblemAttributes.put("RedefinedArgument", SKIP); expectedProblemAttributes.put("RedefinedLocal", SKIP); + 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); 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.12 diff -u -r1.12 NullReferenceImplTests.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java 9 Sep 2010 17:36:17 -0000 1.12 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java 1 Feb 2011 05:32:37 -0000 @@ -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); } 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.109 diff -u -r1.109 NullReferenceTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 19 Jan 2011 05:29:57 -0000 1.109 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 1 Feb 2011 05:32:37 -0000 @@ -36,7 +36,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[] { "testBug325229" }; + TESTS_NAMES = new String[] { "testBug247564h_1" }; // TESTS_NUMBERS = new int[] { 561 }; // TESTS_RANGE = new int[] { 1, 2049 }; } @@ -96,13 +96,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" ); } @@ -333,13 +332,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" ); } @@ -355,13 +353,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" ); } @@ -411,13 +408,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" ); } @@ -436,13 +432,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" ); } @@ -13673,6 +13668,549 @@ "}"}, "null220"); } + +// 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 field2;\n" + + " }\n" + + "}\n"}, + "----------\n" + + "1. ERROR in X.java (at line 9)\n" + + " if (field3 == null && field3.toString() == \"\"){}\n" + + " ^^^^^^\n" + + "Potential null pointer access: The field field3 may be null at this location\n" + + "----------\n" + ); +} // https://bugs.eclipse.org/bugs/show_bug.cgi?id=332637 // Dead Code detection removing code that isn't dead public void testBug332637() {