### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java,v retrieving revision 1.2 diff -u -r1.2 CompletionOnBranchStatementLabel.java --- codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java 7 Mar 2009 00:59:00 -0000 1.2 +++ codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java 30 Nov 2010 14:41:46 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2009 IBM Corporation and others. + * Copyright (c) 2005, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.codeassist.complete; @@ -28,8 +29,7 @@ this.possibleLabels = possibleLabels; } - public FlowInfo analyseCode(BlockScope currentScope, - FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // Is never called return null; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java,v retrieving revision 1.45 diff -u -r1.45 AND_AND_Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java 12 Aug 2010 16:58:28 -0000 1.45 +++ compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java 30 Nov 2010 14:41:46 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -27,7 +29,7 @@ super(left, right, operator); } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { Constant cst = this.left.optimizedBooleanConstant(); boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; @@ -38,15 +40,15 @@ // need to be careful of scenario: // (x && y) && !z, if passing the left info to the right, it would // be swapped by the ! - FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo) + FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, false) // subject to optimization .unconditionalInits(); - mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo); + mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo, valueRequired); this.mergedInitStateIndex = currentScope.methodScope() .recordInitializationStates(mergedInfo); return mergedInfo; } - FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo); + FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired); // need to be careful of scenario: // (x && y) && !z, if passing the left info to the right, it would be // swapped by the ! @@ -60,7 +62,7 @@ rightInfo.setReachMode(FlowInfo.UNREACHABLE); } } - rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo); + rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo, !isLeftOptimizedFalse); // unused if left is false if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) { this.left.checkNPE(currentScope, flowContext, flowInfo); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java,v retrieving revision 1.104 diff -u -r1.104 ASTNode.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java 22 Oct 2010 22:42:55 -0000 1.104 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java 30 Nov 2010 14:41:47 -0000 @@ -9,7 +9,9 @@ * IBM Corporation - initial API and implementation * Matt McCutchen - partial fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=122995 * Karen Moore - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=207411 - * Stephan Herrmann - Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann - Contributions for + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -156,6 +158,7 @@ // for references on lhs of assignment public static final int IsStrictlyAssigned = Bit14; // set only for true assignments, as opposed to compound ones public static final int IsCompoundAssigned = Bit17; // set only for compound assignments, as opposed to other ones + public static final int IsInsideCondition = Bit21; // for name/field reference inside a condition // for explicit constructor call public static final int DiscardEnclosingInstance = Bit14; // used for codegen @@ -364,7 +367,7 @@ && field.isOrEnclosedByPrivateType() && !scope.isDefinedInField(field)) // ignore cases where field is used from inside itself { - if (((filteredBits & IsCompoundAssigned) != 0)) + if (((filteredBits & (IsCompoundAssigned|IsInsideCondition)) != 0)) // used, but usage may not be relevant field.original().compoundUseFlag++; else Index: compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java,v retrieving revision 1.36 diff -u -r1.36 AbstractVariableDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java 6 May 2010 18:37:17 -0000 1.36 +++ compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java 30 Nov 2010 14:41:47 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -36,7 +37,7 @@ public TypeReference type; - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { return flowInfo; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java,v retrieving revision 1.84 diff -u -r1.84 AllocationExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java 12 Aug 2010 16:58:28 -0000 1.84 +++ compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java 30 Nov 2010 14:41:48 -0000 @@ -10,6 +10,7 @@ * Stephan Herrmann - Contributions for * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -30,7 +31,9 @@ public TypeBinding[] genericTypeArguments; public FieldDeclaration enumConstant; // for enum constant initializations -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // constructor may have side effect => require values from all child nodes + // check captured variables are initialized in current context (26134) checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo); @@ -39,7 +42,7 @@ for (int i = 0, count = this.arguments.length; i < count; i++) { flowInfo = this.arguments[i] - .analyseCode(currentScope, flowContext, flowInfo) + .analyseCode(currentScope, flowContext, flowInfo, true) .unconditionalInits(); if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); Index: compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java,v retrieving revision 1.44 diff -u -r1.44 ArrayAllocationExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java 12 Aug 2010 16:58:28 -0000 1.44 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java 30 Nov 2010 14:41:48 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -26,18 +28,21 @@ public Expression[] dimensions; public ArrayInitializer initializer; - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // allocation itself has no side effect => may optimize all child nodes + for (int i = 0, max = this.dimensions.length; i < max; i++) { Expression dim; if ((dim = this.dimensions[i]) != null) { - flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo); - if ((dim.implicitConversion & TypeIds.UNBOXING) != 0) { + boolean isUnboxing = (dim.implicitConversion & TypeIds.UNBOXING) != 0; + flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo, valueRequired || isUnboxing); + if (isUnboxing) { dim.checkNPE(currentScope, flowContext, flowInfo); } } } if (this.initializer != null) { - return this.initializer.analyseCode(currentScope, flowContext, flowInfo); + return this.initializer.analyseCode(currentScope, flowContext, flowInfo, valueRequired); } return flowInfo; } @@ -58,22 +63,23 @@ for (int i = 0, max = this.dimensions.length; i < max; i++) { Expression dimExpression; if ((dimExpression = this.dimensions[i]) == null) break; // implicit dim, no further explict after this point - dimExpression.generateCode(currentScope, codeStream, true); + boolean isUnboxing = (dimExpression.implicitConversion & TypeIds.UNBOXING) != 0; + dimExpression.generateCode(currentScope, codeStream, valueRequired || isUnboxing); + if (!valueRequired && isUnboxing) + codeStream.pop(); explicitDimCount++; } - // array allocation - if (explicitDimCount == 1) { - // Mono-dimensional array - codeStream.newArray((ArrayBinding)this.resolvedType); - } else { - // Multi-dimensional array - codeStream.multianewarray(this.resolvedType, explicitDimCount); - } if (valueRequired) { + // array allocation + if (explicitDimCount == 1) { + // Mono-dimensional array + codeStream.newArray((ArrayBinding)this.resolvedType); + } else { + // Multi-dimensional array + codeStream.multianewarray(this.resolvedType, explicitDimCount); + } codeStream.generateImplicitConversion(this.implicitConversion); - } else { - codeStream.pop(); } codeStream.recordPositionsFrom(pc, this.sourceStart); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java,v retrieving revision 1.55 diff -u -r1.55 ArrayInitializer.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java 7 Mar 2009 00:58:58 -0000 1.55 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java 30 Nov 2010 14:41:48 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -29,11 +30,12 @@ super(); } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // initializer itself has no side effect => may optimize all child nodes if (this.expressions != null) { for (int i = 0, max = this.expressions.length; i < max; i++) { - flowInfo = this.expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + flowInfo = this.expressions[i].analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(); } } return flowInfo; @@ -47,6 +49,12 @@ // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers int pc = codeStream.position; int expressionLength = (this.expressions == null) ? 0: this.expressions.length; + if (!valueRequired) { + // no side effects in this node -> only generate side effects of dim expressions + for (int i = 0; i < expressionLength; i++) + this.expressions[i].generateCode(currentScope, codeStream, false); + return; + } codeStream.generateInlinedValue(expressionLength); codeStream.newArray(this.binding); if (this.expressions != null) { @@ -102,11 +110,7 @@ } } } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - codeStream.pop(); - } + codeStream.generateImplicitConversion(this.implicitConversion); codeStream.recordPositionsFrom(pc, this.sourceStart); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java,v retrieving revision 1.51 diff -u -r1.51 ArrayReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java 25 Sep 2008 23:10:29 -0000 1.51 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java 30 Nov 2010 14:41:50 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -31,23 +32,25 @@ this.sourceStart = rec.sourceStart; } -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean compoundAssignment) { +public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean compoundAssignment, boolean valueRequired) { + // array assignment has a side effect => require values from all child nodes + // TODO (maxime) optimization: unconditionalInits is applied to all existing calls if (assignment.expression == null) { - return analyseCode(currentScope, flowContext, flowInfo); + return analyseCode(currentScope, flowContext, flowInfo, true); } return assignment .expression .analyseCode( currentScope, flowContext, - analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()); + analyseCode(currentScope, flowContext, flowInfo, true).unconditionalInits(), true); } - -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // reference itself has no side effect => may optimize all child nodes this.receiver.checkNPE(currentScope, flowContext, flowInfo); - flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo); - return this.position.analyseCode(currentScope, flowContext, flowInfo); + flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, valueRequired); + return this.position.analyseCode(currentScope, flowContext, flowInfo, valueRequired); } public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { @@ -71,6 +74,13 @@ */ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { int pc = codeStream.position; + if (!valueRequired) { + // reference itself has no side effect => optimize all child nodes + this.receiver.generateCode(currentScope, codeStream, false); + this.position.generateCode(currentScope, codeStream, false); + codeStream.recordPositionsFrom(pc, this.sourceStart); + return; + } this.receiver.generateCode(currentScope, codeStream, true); if (this.receiver instanceof CastExpression // ((type[])null)[0] && ((CastExpression)this.receiver).innermostCastedExpression().resolvedType == TypeBinding.NULL){ Index: compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java,v retrieving revision 1.66 diff -u -r1.66 AssertStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java 22 Oct 2010 04:15:15 -0000 1.66 +++ compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java 30 Nov 2010 14:41:50 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -40,7 +42,8 @@ this.sourceEnd = assertExpression.sourceEnd; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // assert may have side effect (throwing) => require values from all child nodes this.preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); Constant cst = this.assertExpression.optimizedBooleanConstant(); @@ -51,7 +54,7 @@ boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false; flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING; - FlowInfo conditionFlowInfo = this.assertExpression.analyseCode(currentScope, flowContext, flowInfo.copy()); + FlowInfo conditionFlowInfo = this.assertExpression.analyseCode(currentScope, flowContext, flowInfo.copy(), true); flowContext.tagBits &= ~FlowContext.HIDE_NULL_COMPARISON_WARNING; UnconditionalFlowInfo assertWhenTrueInfo = conditionFlowInfo.initsWhenTrue().unconditionalInits(); FlowInfo assertInfo = conditionFlowInfo.initsWhenFalse(); @@ -61,7 +64,7 @@ if (this.exceptionArgument != null) { // only gets evaluated when escaping - results are not taken into account - FlowInfo exceptionInfo = this.exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); + FlowInfo exceptionInfo = this.exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy(), true); if (isOptimizedTrueAssertion){ currentScope.problemReporter().fakeReachable(this.exceptionArgument); 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.92 diff -u -r1.92 Assignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 9 Sep 2010 17:36:20 -0000 1.92 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 30 Nov 2010 14:41:50 -0000 @@ -8,8 +8,10 @@ * Contributors: * IBM Corporation - initial API and implementation * Genady Beriozkin - added support for reporting assignment with no effect - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * and bug 292478 - Report potentially null across variable assignment + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 292478 - Report potentially null across variable assignment + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -34,7 +36,7 @@ this.sourceEnd = sourceEnd; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // 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. @@ -50,7 +52,7 @@ } } flowInfo = ((Reference) this.lhs) - .analyseAssignment(currentScope, flowContext, flowInfo, this, false) + .analyseAssignment(currentScope, flowContext, flowInfo, this, false, valueRequired) .unconditionalInits(); if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { flowInfo.markNullStatus(local, nullStatus); Index: compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java,v retrieving revision 1.68 diff -u -r1.68 BinaryExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 26 Nov 2008 17:56:55 -0000 1.68 +++ compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 30 Nov 2010 14:41:53 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -56,18 +57,18 @@ this.sourceStart = expression.sourceStart; this.sourceEnd = expression.sourceEnd; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // keep implementation in sync with CombinedBinaryExpression#analyseCode if (this.resolvedType.id == TypeIds.T_JavaLangString) { return this.right.analyseCode( currentScope, flowContext, - this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()) + this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(), valueRequired) .unconditionalInits(); } else { this.left.checkNPE(currentScope, flowContext, flowInfo); - flowInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + flowInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(); this.right.checkNPE(currentScope, flowContext, flowInfo); - return this.right.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + return this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(); } } 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 30 Nov 2010 14:41:53 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -26,14 +27,14 @@ this.explicitDeclarations = explicitDeclarations; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // empty block if (this.statements == null) return flowInfo; int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; for (int i = 0, max = this.statements.length; i < max; i++) { Statement stat = this.statements[i]; if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { - flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo); + flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo, false); } } return flowInfo; Index: compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java,v retrieving revision 1.14 diff -u -r1.14 BreakStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java 13 Sep 2010 13:26:20 -0000 1.14 +++ compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java 30 Nov 2010 14:41:53 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -20,7 +21,7 @@ super(label, sourceStart, e); } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // here requires to generate a sequence of finally blocks invocations depending corresponding // to each of the traversed try statements, so that execution will terminate properly. Index: compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java,v retrieving revision 1.35 diff -u -r1.35 CaseStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java 13 Sep 2010 13:26:20 -0000 1.35 +++ compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java 30 Nov 2010 14:41:54 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -35,17 +36,14 @@ this.sourceStart = sourceStart; } -public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { if (this.constantExpression != null) { if (this.constantExpression.constant == Constant.NotAConstant && !this.constantExpression.resolvedType.isEnum()) { currentScope.problemReporter().caseExpressionMustBeConstant(this.constantExpression); } - this.constantExpression.analyseCode(currentScope, flowContext, flowInfo); + this.constantExpression.analyseCode(currentScope, flowContext, flowInfo, true); // nothing to optimize here } 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.136 diff -u -r1.136 CastExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java 12 Aug 2010 16:58:28 -0000 1.136 +++ compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java 30 Nov 2010 14:41:54 -0000 @@ -8,7 +8,9 @@ * Contributors: * IBM Corporation - initial API and implementation * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -47,11 +49,13 @@ type.bits |= ASTNode.IgnoreRawTypeCheck; // no need to worry about raw type usage } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + boolean isUnboxing = (this.expression.implicitConversion & TypeIds.UNBOXING) != 0; + boolean canThrow = isUnboxing || (this.bits & ASTNode.UnnecessaryCast) == 0; FlowInfo result = this.expression - .analyseCode(currentScope, flowContext, flowInfo) + .analyseCode(currentScope, flowContext, flowInfo, valueRequired||canThrow) // may optimize if no side effect by throwing (NPE or CCE) .unconditionalInits(); - if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { + if (isUnboxing) { this.expression.checkNPE(currentScope, flowContext, flowInfo); } return result; Index: compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java,v retrieving revision 1.53 diff -u -r1.53 ClassLiteralAccess.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java 1 Nov 2010 14:44:53 -0000 1.53 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java 30 Nov 2010 14:41:54 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -30,10 +31,7 @@ this.sourceEnd = sourceEnd; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // if reachable, request the addition of a synthetic field for caching the class descriptor SourceTypeBinding sourceType = currentScope.outerMostClassScope().enclosingSourceType(); Index: compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java,v retrieving revision 1.5 diff -u -r1.5 CombinedBinaryExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java 27 Jun 2008 16:03:56 -0000 1.5 +++ compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java 30 Nov 2010 14:41:55 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -116,17 +117,17 @@ } public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, - FlowInfo flowInfo) { + FlowInfo flowInfo, boolean valueRequired) { // keep implementation in sync with BinaryExpression#analyseCode if (this.referencesTable == null) { - return super.analyseCode(currentScope, flowContext, flowInfo); + return super.analyseCode(currentScope, flowContext, flowInfo, valueRequired); } BinaryExpression cursor; if ((cursor = this.referencesTable[0]).resolvedType.id != TypeIds.T_JavaLangString) { cursor.left.checkNPE(currentScope, flowContext, flowInfo); } - flowInfo = cursor.left.analyseCode(currentScope, flowContext, flowInfo). + flowInfo = cursor.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired). unconditionalInits(); for (int i = 0, end = this.arity; i < end; i ++) { if ((cursor = this.referencesTable[i]).resolvedType.id != @@ -134,13 +135,13 @@ cursor.right.checkNPE(currentScope, flowContext, flowInfo); } flowInfo = cursor.right. - analyseCode(currentScope, flowContext, flowInfo). + analyseCode(currentScope, flowContext, flowInfo, valueRequired). unconditionalInits(); } if (this.resolvedType.id != TypeIds.T_JavaLangString) { this.right.checkNPE(currentScope, flowContext, flowInfo); } - return this.right.analyseCode(currentScope, flowContext, flowInfo). + return this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired). unconditionalInits(); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java,v retrieving revision 1.60 diff -u -r1.60 CompoundAssignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java 22 Jul 2009 17:08:54 -0000 1.60 +++ compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java 30 Nov 2010 14:41:55 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -34,16 +35,16 @@ this.operator = operator ; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, - FlowInfo flowInfo) { - // 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. - if (this.resolvedType.id != T_JavaLangString) { - this.lhs.checkNPE(currentScope, flowContext, flowInfo); + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, + FlowInfo flowInfo, boolean valueRequired) { + // 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. + if (this.resolvedType.id != T_JavaLangString) { + this.lhs.checkNPE(currentScope, flowContext, flowInfo); + } + return ((Reference) this.lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true, valueRequired).unconditionalInits(); } - return ((Reference) this.lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits(); -} public boolean checkCastCompatibility() { return true; Index: compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java,v retrieving revision 1.97 diff -u -r1.97 ConditionalExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java 9 Sep 2010 17:36:20 -0000 1.97 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java 30 Nov 2010 14:41:57 -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 @@ -7,7 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephen Herrmann - Contributions for bugs 133125, 292478 + * Stephen Herrmann - Contributions for + * bug 133125 - [compiler][null] need to report the null status of expressions and analyze them simultaneously + * bug 292478 - Report potentially null across variable assignment + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -40,16 +43,15 @@ this.sourceStart = condition.sourceStart; this.sourceEnd = valueIfFalse.sourceEnd; } - -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, + FlowInfo flowInfo, boolean valueRequired) { int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; Constant cst = this.condition.optimizedBooleanConstant(); boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; int mode = flowInfo.reachMode(); - flowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo, cst == Constant.NotAConstant); + flowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo, valueRequired && (cst == Constant.NotAConstant)); // process the if-true part FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy(); @@ -62,7 +64,7 @@ } } this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo); - trueFlowInfo = this.valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo); + trueFlowInfo = this.valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo, valueRequired); // process the if-false part FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy(); @@ -75,7 +77,7 @@ } } this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo); - falseFlowInfo = this.valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo); + falseFlowInfo = this.valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo, valueRequired); // merge if-true & if-false initializations FlowInfo mergedInfo; Index: compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java,v retrieving revision 1.112 diff -u -r1.112 ConstructorDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java 9 Nov 2010 19:59:19 -0000 1.112 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java 30 Nov 2010 14:41:58 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -139,7 +140,7 @@ } } } - flowInfo = this.constructorCall.analyseCode(this.scope, constructorContext, flowInfo); + flowInfo = this.constructorCall.analyseCode(this.scope, constructorContext, flowInfo, false); // called as a statement } // reuse the reachMode from non static field info @@ -151,7 +152,7 @@ for (int i = 0, count = this.statements.length; i < count; i++) { Statement stat = this.statements[i]; if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { - flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo); + flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo, false); // ignore any values produced by statements } } } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java,v retrieving revision 1.13 diff -u -r1.13 ContinueStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java 7 Mar 2009 01:08:07 -0000 1.13 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java 30 Nov 2010 14:41:58 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -20,7 +21,7 @@ super(label, sourceStart, sourceEnd); } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // here requires to generate a sequence of finally blocks invocations depending corresponding // to each of the traversed try statements, so that execution will terminate properly. Index: compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java,v retrieving revision 1.62 diff -u -r1.62 DoStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java 23 Aug 2010 08:41:25 -0000 1.62 +++ compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java 30 Nov 2010 14:41:58 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -38,7 +40,8 @@ if (action instanceof EmptyStatement) action.bits |= ASTNode.IsUsefulEmptyStatement; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + this.breakLabel = new BranchLabel(); this.continueLabel = new BranchLabel(); LoopingFlowContext loopingContext = @@ -66,7 +69,7 @@ // or catch blocks if ((this.action != null) && !this.action.isEmptyBlock()) { actionInfo = this.action. - analyseCode(currentScope, loopingContext, actionInfo). + analyseCode(currentScope, loopingContext, actionInfo, false). // statements, values are ignored unconditionalInits(); // code generation can be optimized when no need to continue in the loop @@ -100,7 +103,8 @@ null, currentScope)), (this.action == null ? actionInfo - : (actionInfo.mergedWith(loopingContext.initsOnContinue))).copy()); + : (actionInfo.mergedWith(loopingContext.initsOnContinue))).copy(), + !isConditionOptimizedFalse); // subject to optimization if constant false this.preConditionInitStateIndex = currentScope.methodScope().recordInitializationStates(actionInfo); if (!isConditionOptimizedFalse && this.continueLabel != null) { loopingContext.complainOnDeferredFinalChecks(currentScope, condInfo); @@ -206,7 +210,13 @@ } public void resolve(BlockScope scope) { - TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + TypeBinding type = null; + try { + scope.isInsideCondition = true; + type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + } finally { + scope.isInsideCondition = false; + } this.condition.computeConversion(scope, type, type); if (this.action != null) this.action.resolve(scope); Index: compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java,v retrieving revision 1.26 diff -u -r1.26 EmptyStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java 7 Mar 2009 01:08:07 -0000 1.26 +++ compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java 30 Nov 2010 14:41:58 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -24,7 +25,7 @@ this.sourceEnd = endPosition; } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { return flowInfo; } @@ -52,6 +53,10 @@ scope.problemReporter().emptyControlFlowStatement(this.sourceStart, this.sourceEnd); } } + + public boolean isEmptyBlock() { + return true; + } public void traverse(ASTVisitor visitor, BlockScope scope) { visitor.visit(this, scope); 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 30 Nov 2010 14:41:59 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -69,55 +70,59 @@ // does not preclude the variable from being null in an enclosing scope } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) + { FlowInfo result; if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) { if (this.left.constant.booleanValue()) { // true == anything // this is equivalent to the right argument inits - result = this.right.analyseCode(currentScope, flowContext, flowInfo); + result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired); } else { // false == anything // this is equivalent to the right argument inits negated - result = this.right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition(); } } else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) { if (this.right.constant.booleanValue()) { // anything == true // this is equivalent to the left argument inits - result = this.left.analyseCode(currentScope, flowContext, flowInfo); + result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired); } else { // anything == false // this is equivalent to the right argument inits negated - result = this.left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition(); } } else { result = this.right.analyseCode( - currentScope, flowContext, - this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits(); + currentScope, flowContext, + this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(), + valueRequired). + unconditionalInits(); } } else { //NOT_EQUAL : if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) { if (!this.left.constant.booleanValue()) { // false != anything // this is equivalent to the right argument inits - result = this.right.analyseCode(currentScope, flowContext, flowInfo); + result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired); } else { // true != anything // this is equivalent to the right argument inits negated - result = this.right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition(); } } else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) { if (!this.right.constant.booleanValue()) { // anything != false // this is equivalent to the right argument inits - result = this.left.analyseCode(currentScope, flowContext, flowInfo); + result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired); } else { // anything != true // this is equivalent to the right argument inits negated - result = this.left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); + result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition(); } } else { result = this.right.analyseCode( - currentScope, flowContext, - this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()). + currentScope, flowContext, + this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(), + valueRequired). /* unneeded since we flatten it: asNegatedCondition(). */ unconditionalInits(); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java,v retrieving revision 1.74 diff -u -r1.74 ExplicitConstructorCall.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java 12 Aug 2010 16:58:28 -0000 1.74 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java 30 Nov 2010 14:42:01 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -57,7 +59,9 @@ this.accessMode = accessMode; } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // called constructor may have side effect => require values from all child nodes + // must verify that exceptions potentially thrown by this expression are caught in the method. try { @@ -67,7 +71,7 @@ if (this.qualification != null) { flowInfo = this.qualification - .analyseCode(currentScope, flowContext, flowInfo) + .analyseCode(currentScope, flowContext, flowInfo, true) .unconditionalInits(); } // process arguments @@ -75,7 +79,7 @@ for (int i = 0, max = this.arguments.length; i < max; i++) { flowInfo = this.arguments[i] - .analyseCode(currentScope, flowContext, flowInfo) + .analyseCode(currentScope, flowContext, flowInfo, true) .unconditionalInits(); if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, 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.131 diff -u -r1.131 Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 15 Sep 2010 16:10:50 -0000 1.131 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java 30 Nov 2010 14:42:02 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 292478 - Report potentially null across variable assignment + * Stephan Herrmann - Contributions for + * bug 292478 - Report potentially null across variable assignment + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -207,10 +209,6 @@ super(); } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return flowInfo; -} - /** * More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out * portions of expressions where no actual value is required. @@ -222,7 +220,7 @@ * @return The state of initialization after the analysis of the current expression */ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { - return analyseCode(currentScope, flowContext, flowInfo); + return flowInfo; } /** 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.101 diff -u -r1.101 FieldDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java 1 Jul 2010 04:39:20 -0000 1.101 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java 30 Nov 2010 14:42:02 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -71,7 +72,7 @@ if (this.initialization != null) { flowInfo = this.initialization - .analyseCode(initializationScope, flowContext, flowInfo) + .analyseCode(initializationScope, flowContext, flowInfo, true) // side effect => require values .unconditionalInits(); flowInfo.markAsDefinitelyAssigned(this.binding); } 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.130 diff -u -r1.130 FieldReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 22 Oct 2010 22:42:55 -0000 1.130 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 30 Nov 2010 14:42:03 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann - Contributions for + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -59,7 +61,11 @@ } -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { +public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) { + // generally, the assignment side effect requires all values from child nodes + // - only the receiver of static field access can be optimized out + // assigning to a field doesn't necessarily mark the field as used, only if the value of the assignment itself is used + // compound assignment extra work if (isCompound) { // check the variable part is initialized if blank final if (this.binding.isBlankFinal() @@ -72,6 +78,8 @@ } } manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830 + reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired); } flowInfo = this.receiver @@ -81,7 +89,7 @@ flowInfo = assignment .expression - .analyseCode(currentScope, flowContext, flowInfo) + .analyseCode(currentScope, flowContext, flowInfo, true) .unconditionalInits(); } manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/); @@ -111,12 +119,10 @@ return flowInfo; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return analyseCode(currentScope, flowContext, flowInfo, true); -} - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { boolean nonStatic = !this.binding.isStatic(); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830 + reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired); this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic); if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); @@ -291,8 +297,6 @@ public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { boolean isStatic; - // check if compound assignment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired); FieldBinding codegenBinding = this.binding.original(); this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic())); if (isStatic) { @@ -340,8 +344,6 @@ public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { boolean isStatic; - // check if postIncrement is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired); FieldBinding codegenBinding = this.binding.original(); this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic())); if (isStatic) { @@ -523,6 +525,9 @@ // constants are propaged when the field is final // and initialized with a (compile time) constant + if (scope.isInsideCondition) + this.bits |= ASTNode.IsInsideCondition; + //always ignore receiver cast, since may affect constant pool reference boolean receiverCast = false; if (this.receiver instanceof CastExpression) { Index: compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java,v retrieving revision 1.69 diff -u -r1.69 ForStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java 23 Aug 2010 08:41:25 -0000 1.69 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java 30 Nov 2010 14:42:05 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -59,7 +61,7 @@ } } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { this.breakLabel = new BranchLabel(); this.continueLabel = new BranchLabel(); int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; @@ -67,7 +69,7 @@ // process the initializations if (this.initializations != null) { for (int i = 0, count = this.initializations.length; i < count; i++) { - flowInfo = this.initializations[i].analyseCode(this.scope, flowContext, flowInfo); + flowInfo = this.initializations[i].analyseCode(this.scope, flowContext, flowInfo, false); } } this.preCondInitStateIndex = @@ -92,7 +94,8 @@ (condLoopContext = new LoopingFlowContext(flowContext, flowInfo, this, null, null, this.scope)), - condInfo); + condInfo, + !isConditionOptimizedFalse); if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) { this.condition.checkNPE(currentScope, flowContext, flowInfo); } @@ -139,7 +142,7 @@ } } if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { - actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits(); + actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo, false).unconditionalInits(); } // code generation can be optimized when no need to continue in the loop @@ -172,7 +175,7 @@ currentScope.methodScope().recordInitializationStates(incrementInfo); for (int i = 0, count = this.increments.length; i < count; i++) { incrementInfo = this.increments[i]. - analyseCode(this.scope, incrementContext, incrementInfo); + analyseCode(this.scope, incrementContext, incrementInfo, false); } incrementContext.complainOnDeferredFinalChecks(this.scope, actionInfo = incrementInfo.unconditionalInits()); @@ -377,7 +380,13 @@ for (int i = 0, length = this.initializations.length; i < length; i++) this.initializations[i].resolve(this.scope); if (this.condition != null) { - TypeBinding type = this.condition.resolveTypeExpecting(this.scope, TypeBinding.BOOLEAN); + TypeBinding type = null; + try { + upperScope.isInsideCondition = true; + type = this.condition.resolveTypeExpecting(this.scope, TypeBinding.BOOLEAN); + } finally { + upperScope.isInsideCondition = false; + } this.condition.computeConversion(this.scope, type, type); } if (this.increments != null) Index: compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java,v retrieving revision 1.64 diff -u -r1.64 ForeachStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java 9 Aug 2010 04:09:41 -0000 1.64 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java 30 Nov 2010 14:42:05 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -72,7 +73,7 @@ this.kind = -1; } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // initialize break and continue labels this.breakLabel = new BranchLabel(); this.continueLabel = new BranchLabel(); @@ -80,8 +81,8 @@ // process the element variable and collection this.collection.checkNPE(currentScope, flowContext, flowInfo); - flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo); - FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy()); + flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo, false); // analyse as a statement -> ignore value + FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy(), true); // collection value is required // element variable will be assigned when iterating condInfo.markAsDefinitelyAssigned(this.elementVariable.binding); @@ -100,7 +101,7 @@ && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) { if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { - actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy(); + actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo, false).unconditionalCopy(); // statement values are ignored } // code generation can be optimized when no need to continue in the loop Index: compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java,v retrieving revision 1.69 diff -u -r1.69 IfStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java 12 Aug 2010 16:58:28 -0000 1.69 +++ compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java 30 Nov 2010 14:42:06 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -52,17 +54,34 @@ this.sourceEnd = sourceEnd; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // process the condition - FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo); + Constant cst = this.condition.optimizedBooleanConstant(); + + boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; + boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; + boolean hasThenPart = this.thenStatement != null && !this.thenStatement.isEmptyBlock(); + boolean hasElsePart = this.elseStatement != null && !this.elseStatement.isEmptyBlock(); + + boolean conditionValueRequired = true; + if (hasThenPart) { + // will generate boolean condition only if needed + if (isConditionOptimizedTrue) + conditionValueRequired = false; + } else if (hasElsePart) { + // will generate boolean condition only if needed + if (isConditionOptimizedFalse) + conditionValueRequired = false; + } else { + conditionValueRequired = false; + } + + FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo, conditionValueRequired); int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - Constant cst = this.condition.optimizedBooleanConstant(); if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) { this.condition.checkNPE(currentScope, flowContext, flowInfo); } - boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; // process the THEN part FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue(); @@ -96,7 +115,7 @@ this.bits &= ~ASTNode.IsThenStatementUnreachable; } } - thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); + thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo, false); // analyse as statement, ignore value } // code gen: optimizing the jump around the ELSE part if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) { @@ -122,7 +141,7 @@ this.bits &= ~ASTNode.IsElseStatementUnreachable; } } - elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); + elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo, false); // analyse as statement, ignore value } // merge THEN & ELSE initializations FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranchesIfElse( @@ -260,7 +279,13 @@ } public void resolve(BlockScope scope) { - TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + TypeBinding type = null; + try { + scope.isInsideCondition = true; + type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + } finally { + scope.isInsideCondition = false; + } this.condition.computeConversion(scope, type, type); if (this.thenStatement != null) this.thenStatement.resolve(scope); Index: compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java,v retrieving revision 1.44 diff -u -r1.44 Initializer.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java 7 Mar 2009 01:08:07 -0000 1.44 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java 30 Nov 2010 14:42:06 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -33,13 +34,10 @@ } } - public FlowInfo analyseCode( - MethodScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(MethodScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { if (this.block != null) { - return this.block.analyseCode(currentScope, flowContext, flowInfo); + return this.block.analyseCode(currentScope, flowContext, flowInfo, false); // statements, ignore value } return flowInfo; } 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 30 Nov 2010 14:42:06 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -30,10 +31,10 @@ this.sourceEnd = type.sourceEnd; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { LocalVariableBinding local = this.expression.localVariableBinding(); if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo). + flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo, valueRequired). unconditionalInits(); FlowInfo initsWhenTrue = flowInfo.copy(); initsWhenTrue.markAsComparedEqualToNonNull(local); @@ -45,7 +46,7 @@ // no impact upon enclosing try context return FlowInfo.conditional(initsWhenTrue, flowInfo.copy()); } - return this.expression.analyseCode(currentScope, flowContext, flowInfo). + return this.expression.analyseCode(currentScope, flowContext, flowInfo, valueRequired). unconditionalInits(); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java,v retrieving revision 1.40 diff -u -r1.40 LabeledStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java 27 Jun 2008 16:03:55 -0000 1.40 +++ compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java 30 Nov 2010 14:42:06 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -39,10 +40,7 @@ this.sourceEnd = sourceEnd; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // need to stack a context to store explicit label, answer inits in case of normal completion merged // with those relative to the exit path from break statement occurring inside the labeled statement. @@ -60,7 +58,8 @@ this.label, (this.targetLabel = new BranchLabel()), currentScope)), - flowInfo); + flowInfo, + false); // statement, value ignored boolean reinjectNullInfo = (statementInfo.tagBits & FlowInfo.UNREACHABLE) != 0 && (labelContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) == 0; mergedInfo = statementInfo.mergedWith(labelContext.initsOnBreak); Index: compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java,v retrieving revision 1.18 diff -u -r1.18 Literal.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java 7 Mar 2009 01:08:07 -0000 1.18 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java 30 Nov 2010 14:42:06 -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 @@ -7,11 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.*; import org.eclipse.jdt.internal.compiler.lookup.*; @@ -23,14 +22,6 @@ this.sourceEnd = e; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - return flowInfo; - } - public abstract void computeConstant(); public abstract TypeBinding literalType(BlockScope scope); Index: compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java,v retrieving revision 1.74 diff -u -r1.74 LocalDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 9 Sep 2010 17:36:21 -0000 1.74 +++ compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 30 Nov 2010 14:42:08 -0000 @@ -7,8 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * and bug 292478 - Report potentially null across variable assignment + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 292478 - Report potentially null across variable assignment + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -34,35 +36,35 @@ this.declarationEnd = sourceEnd; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // record variable initialization if any - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - this.bits |= ASTNode.IsLocalDeclarationReachable; // only set if actually reached - } - if (this.initialization == null) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // record variable initialization if any + if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { + this.bits |= ASTNode.IsLocalDeclarationReachable; // only set if actually reached + } + if (this.initialization == null) { + return flowInfo; + } + if ((this.initialization.implicitConversion & TypeIds.UNBOXING) != 0) { + this.initialization.checkNPE(currentScope, flowContext, flowInfo); + } + int nullStatus = this.initialization.nullStatus(flowInfo); + flowInfo = + this.initialization + .analyseCode(currentScope, flowContext, flowInfo, true) // at this point we must assume that the local is used, thus the side effect requires the value + .unconditionalInits(); + if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes + this.bits |= FirstAssignmentToLocal; + } else { + this.bits &= ~FirstAssignmentToLocal; // int i = (i = 0); + } + flowInfo.markAsDefinitelyAssigned(this.binding); + if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) { + flowInfo.markNullStatus(this.binding, nullStatus); + // no need to inform enclosing try block since its locals won't get + // known by the finally block + } return flowInfo; } - if ((this.initialization.implicitConversion & TypeIds.UNBOXING) != 0) { - this.initialization.checkNPE(currentScope, flowContext, flowInfo); - } - int nullStatus = this.initialization.nullStatus(flowInfo); - flowInfo = - this.initialization - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes - this.bits |= FirstAssignmentToLocal; - } else { - this.bits &= ~FirstAssignmentToLocal; // int i = (i = 0); - } - flowInfo.markAsDefinitelyAssigned(this.binding); - if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) { - flowInfo.markNullStatus(this.binding, nullStatus); - // no need to inform enclosing try block since its locals won't get - // known by the finally block - } - return flowInfo; -} public void checkModifiers() { 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.148 diff -u -r1.148 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 12 Aug 2010 16:58:28 -0000 1.148 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 30 Nov 2010 14:42:08 -0000 @@ -8,7 +8,9 @@ * Contributors: * IBM Corporation - initial API and implementation * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -56,7 +58,9 @@ public TypeReference[] typeArguments; public TypeBinding[] genericTypeArguments; -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // method execution may have side effect => require values from all child nodes + // - exception: receiver of call to static method boolean nonStatic = !this.binding.isStatic(); flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits(); if (nonStatic) { @@ -69,7 +73,7 @@ if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); } - flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo, true).unconditionalInits(); } } ReferenceBinding[] thrownExceptions; Index: compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java,v retrieving revision 1.76 diff -u -r1.76 MethodDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 3 Nov 2009 15:37:46 -0000 1.76 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 30 Nov 2010 14:42:09 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -86,7 +87,7 @@ for (int i = 0, count = this.statements.length; i < count; i++) { Statement stat = this.statements[i]; if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { - flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo); + flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo, false); } } } Index: compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java,v retrieving revision 1.45 diff -u -r1.45 OR_OR_Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java 12 Aug 2010 16:58:28 -0000 1.45 +++ compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java 30 Nov 2010 14:42:09 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -30,7 +32,8 @@ public FlowInfo analyseCode( BlockScope currentScope, FlowContext flowContext, - FlowInfo flowInfo) { + FlowInfo flowInfo, + boolean valueRequired) { Constant cst = this.left.optimizedBooleanConstant(); boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; @@ -40,14 +43,14 @@ // FALSE || anything // need to be careful of scenario: // (x || y) || !z, if passing the left info to the right, it would be swapped by the ! - FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo); + FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, false).unconditionalInits(); // subject to optimization + mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo, valueRequired); this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); return mergedInfo; } - FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo); + FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired); // need to be careful of scenario: // (x || y) || !z, if passing the left info to the right, it would be swapped by the ! @@ -62,7 +65,7 @@ rightInfo.setReachMode(FlowInfo.UNREACHABLE); } } - rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo); + rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo, !isLeftOptimizedTrue); // unused if left is true if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) { this.left.checkNPE(currentScope, flowContext, flowInfo); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java,v retrieving revision 1.101 diff -u -r1.101 QualifiedAllocationExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java 12 Aug 2010 16:58:28 -0000 1.101 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java 30 Nov 2010 14:42:10 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -54,10 +56,12 @@ anonymousType.allocation = this; } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + // constructor may have side effect => thus require values from all child nodes + // analyse the enclosing instance if (this.enclosingInstance != null) { - flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo); + flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo, true); } // check captured variables are initialized in current context (26134) @@ -71,7 +75,7 @@ // process arguments if (this.arguments != null) { for (int i = 0, count = this.arguments.length; i < count; i++) { - flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo); + flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo, true); if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); } @@ -80,7 +84,7 @@ // analyse the anonymous nested type if (this.anonymousType != null) { - flowInfo = this.anonymousType.analyseCode(currentScope, flowContext, flowInfo); + flowInfo = this.anonymousType.analyseCode(currentScope, flowContext, flowInfo, false); // not a value } // record some dependency information for exception types Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java,v retrieving revision 1.148 diff -u -r1.148 QualifiedNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 22 Oct 2010 22:42:55 -0000 1.148 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 30 Nov 2010 14:42:12 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann - Contributions for + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -60,7 +62,7 @@ this.sourceEnd = sourceEnd; } -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { +public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) { // determine the rank until which we now we do not need any actual value for the field access int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); @@ -116,6 +118,8 @@ } if (isCompound) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830 + reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired); if (otherBindingsCount == 0 && lastFieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) { @@ -131,7 +135,7 @@ flowInfo = assignment .expression - .analyseCode(currentScope, flowContext, flowInfo) + .analyseCode(currentScope, flowContext, flowInfo, true) // assignment side effect => require value .unconditionalInits(); } @@ -161,16 +165,13 @@ return flowInfo; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return analyseCode(currentScope, flowContext, flowInfo, true); -} - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // determine the rank until which we now we do not need any actual value for the field access int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic(); boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; + FieldBinding lastFieldBinding = null; switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD : // reading a field if (needValue || complyTo14) { @@ -186,6 +187,7 @@ currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); } } + lastFieldBinding = fieldBinding; } break; case Binding.LOCAL : // reading a local variable @@ -213,7 +215,11 @@ manageSyntheticAccessIfNecessary(currentScope, this.otherBindings[i], i + 1, flowInfo); } } + lastFieldBinding = this.otherBindings[otherBindingsCount-1]; } + if (lastFieldBinding != null) + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830 + reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired); return flowInfo; } @@ -382,7 +388,6 @@ public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); // check if compound assignment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired); boolean isFirst = lastFieldBinding == this.binding && (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType()) && this.otherBindings == null; // could be dup: next.next.next @@ -434,8 +439,6 @@ public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - // check if this post increment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired); boolean isFirst = lastFieldBinding == this.binding && (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType()) && this.otherBindings == null; // could be dup: next.next.next @@ -919,6 +922,10 @@ // field and/or local are done before type lookups // the only available value for the restrictiveFlag BEFORE // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField + + if (scope.isInsideCondition) + this.bits |= ASTNode.IsInsideCondition; + this.actualReceiverType = scope.enclosingReceiverType(); this.constant = Constant.NotAConstant; if ((this.binding = scope.getBinding(this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) { Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java,v retrieving revision 1.40 diff -u -r1.40 QualifiedThisReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java 27 Jun 2008 16:03:56 -0000 1.40 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java 30 Nov 2010 14:42:12 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -7,14 +7,17 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; public class QualifiedThisReference extends ThisReference { @@ -28,23 +31,6 @@ this.sourceStart = name.sourceStart; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - return flowInfo; - } - - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo, - boolean valueRequired) { - - return flowInfo; - } - /** * Code generation for QualifiedThisReference * Index: compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java,v retrieving revision 1.33 diff -u -r1.33 Reference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java 22 Oct 2010 22:42:55 -0000 1.33 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java 30 Nov 2010 14:42:13 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann - Contributions for + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -18,9 +20,7 @@ import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; @@ -32,11 +32,7 @@ public Reference() { super(); } -public abstract FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound); - -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return flowInfo; -} +public abstract FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired); public FieldBinding fieldBinding() { //this method should be sent one FIELD-tagged references @@ -114,49 +110,4 @@ } } } -/* report a local/arg that is only read from a 'special operator', - * i.e., in a postIncrement expression or a compound assignment, - * where the information is never flowing out off the local/arg. */ -static void reportOnlyUselesslyReadLocal(BlockScope currentScope, LocalVariableBinding localBinding, boolean valueRequired) { - if (localBinding.declaration == null) - return; // secret local - if ((localBinding.declaration.bits & ASTNode.IsLocalDeclarationReachable) == 0) - return; // declaration is unreachable - if (localBinding.useFlag >= LocalVariableBinding.USED) - return; // we're only interested in cases with only compound access (negative count) - - if (valueRequired) { - // access is relevant - localBinding.useFlag = LocalVariableBinding.USED; - return; - } else { - localBinding.useFlag++; - if (localBinding.useFlag != LocalVariableBinding.UNUSED) // have all negative counts been consumed? - return; // still waiting to see more usages of this kind - } - // at this point we know we have something to report - if (localBinding.declaration instanceof Argument) { - // check compiler options to report against unused arguments - MethodScope methodScope = currentScope.methodScope(); - if (methodScope != null) { - MethodBinding method = ((AbstractMethodDeclaration)methodScope.referenceContext()).binding; - - boolean shouldReport = !method.isMain(); - if (method.isImplementing()) { - shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenImplementingAbstract; - } else if (method.isOverriding()) { - shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenOverridingConcrete; - } - - if (shouldReport) { - // report the case of an argument that is unread except through a special operator - currentScope.problemReporter().unusedArgument(localBinding.declaration); - } - } - } else { - // report the case of a local variable that is unread except for a special operator - currentScope.problemReporter().unusedLocalVariable(localBinding.declaration); - } - localBinding.useFlag = LocalVariableBinding.USED; // don't report again -} } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java,v retrieving revision 1.68 diff -u -r1.68 ReturnStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 12 Aug 2010 16:58:28 -0000 1.68 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 30 Nov 2010 14:42:13 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -30,13 +32,13 @@ this.expression = expression ; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // here requires to generate a sequence of finally blocks invocations depending corresponding +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // here requires to generate a sequence of finally blocks invocations depending corresponding // to each of the traversed try statements, so that execution will terminate properly. // lookup the label, this should answer the returnContext if (this.expression != null) { - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); + flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo, true); if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { this.expression.checkNPE(currentScope, flowContext, 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.128 diff -u -r1.128 SingleNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 9 Nov 2010 19:59:19 -0000 1.128 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 30 Nov 2010 14:42:14 -0000 @@ -7,8 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 292478 - Report potentially null across variable assignment, - * Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann - Contributions for + * bug 292478 - Report potentially null across variable assignment, + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -41,6 +43,7 @@ import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.jdt.internal.compiler.problem.AbortMethod; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; +import org.eclipse.jdt.internal.compiler.util.Messages; public class SingleNameReference extends NameReference implements OperatorIds { @@ -57,7 +60,7 @@ this.sourceEnd = (int) pos; } -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { +public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) { boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0; // compound assignment extra work if (isCompound) { // check the variable part is initialized if blank final @@ -72,6 +75,8 @@ } } manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830 + reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding, valueRequired); break; case Binding.LOCAL : // reading a local variable // check if assigning a final blank field @@ -80,21 +85,22 @@ currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); // we could improve error msg here telling "cannot use compound assignment on final local variable" } - if (localBinding.useFlag != LocalVariableBinding.USED) { + if (isReachable) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - // access from compound assignment does not prevent "unused" warning, unless unboxing is involved: - if (isReachable && (this.implicitConversion & TypeIds.UNBOXING) != 0) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830 + // access from compound assignment does not prevent "unused" warning / optimization + if ((this.implicitConversion & TypeIds.UNBOXING) != 0 // cannot optimize if unboxing is involved + || valueRequired) // cannot optimize if value is required + { localBinding.useFlag = LocalVariableBinding.USED; - } else { - // use values < 0 to count the number of compound uses: - if (localBinding.useFlag <= LocalVariableBinding.UNUSED) - localBinding.useFlag--; } + } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { + localBinding.useFlag = LocalVariableBinding.FAKE_USED; } } } if (assignment.expression != null) { - flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo, true).unconditionalInits(); } switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD : // assigning to a field @@ -146,10 +152,6 @@ return flowInfo; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return analyseCode(currentScope, flowContext, flowInfo, true); -} - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD : // reading a field @@ -158,6 +160,8 @@ } // check if reading a final blank field FieldBinding fieldBinding = (FieldBinding) this.binding; + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830 + reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding.original(), valueRequired); if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo); if (!fieldInits.isDefinitelyAssigned(fieldBinding)) { @@ -171,7 +175,12 @@ currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); } if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - localBinding.useFlag = LocalVariableBinding.USED; + // check possibility for optimization (https://bugs.eclipse.org/328830): + if ((this.implicitConversion & TypeIds.UNBOXING) != 0 // cannot optimize if unboxing is involved + || valueRequired) // cannot optimize if value is required + { + localBinding.useFlag = LocalVariableBinding.USED; + } } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { localBinding.useFlag = LocalVariableBinding.FAKE_USED; } @@ -425,9 +434,8 @@ LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; if (localBinding.resolvedPosition == -1) { if (valueRequired) { - // restart code gen - localBinding.useFlag = LocalVariableBinding.USED; - throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null); + currentScope.problemReporter().abortDueToInternalError( + Messages.abort_unexpectedUnresolvedLocal); } codeStream.recordPositionsFrom(pc, this.sourceStart); return; @@ -479,17 +487,6 @@ * are optimized in one access: e.g "a = a + 1" optimized into "a++". */ public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.LOCAL: - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - // check if compound assignment is the only usage of this local - Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired); - break; - case Binding.FIELD: - // check if compound assignment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, (FieldBinding)this.binding, valueRequired); - } this.generateCompoundAssignment( currentScope, codeStream, @@ -534,6 +531,19 @@ break; case Binding.LOCAL : // assigning to a local variable (cannot assign to outer local) LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; + if (!valueRequired + && (localBinding.useFlag == LocalVariableBinding.UNUSED) // analysis did not consider this relevant + && (this.implicitConversion & TypeIds.UNBOXING) == 0) + { + // if no valueRequired and variable unused, generate only side effects + if (expression.constant == Constant.NotAConstant) + expression.generateCode(currentScope, codeStream, false); + return; + } else if (localBinding.resolvedPosition == -1) { + currentScope.problemReporter().abortDueToInternalError( + Messages.abort_unexpectedUnresolvedLocal); + } + // using incr bytecode if possible Constant assignConstant; switch (localBinding.type.id) { @@ -546,21 +556,6 @@ return; case T_int : assignConstant = expression.constant; - if (localBinding.resolvedPosition == -1) { - if (valueRequired) { - /* - * restart code gen because we either: - * - need the value - * - the constant can have potential side-effect - */ - localBinding.useFlag = LocalVariableBinding.USED; - throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null); - } else if (assignConstant == Constant.NotAConstant) { - // we only need to generate the value of the expression's constant if it is not a constant expression - expression.generateCode(currentScope, codeStream, false); - } - return; - } if ((assignConstant != Constant.NotAConstant) && (assignConstant.typeID() != TypeIds.T_float) // only for integral types && (assignConstant.typeID() != TypeIds.T_double)) { // TODO (philippe) is this test needed ? @@ -660,9 +655,6 @@ switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD : // assigning to a field FieldBinding fieldBinding = (FieldBinding)this.binding; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - // check if postIncrement is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding, valueRequired); FieldBinding codegenField = fieldBinding.original(); if (codegenField.isStatic()) { if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) { @@ -726,16 +718,14 @@ return; case Binding.LOCAL : // assigning to a local variable LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - // check if postIncrement is the only usage of this local - Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired); - if (localBinding.resolvedPosition == -1) { - if (valueRequired) { - // restart code gen - localBinding.useFlag = LocalVariableBinding.USED; - throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null); - } + if (!valueRequired + && (localBinding.useFlag == LocalVariableBinding.UNUSED) // analysis did not consider this relevant + && (this.implicitConversion & TypeIds.UNBOXING) == 0) + { return; + } else if (localBinding.resolvedPosition == -1) { + currentScope.problemReporter().abortDueToInternalError( + Messages.abort_unexpectedUnresolvedLocal); } // using incr bytecode if possible @@ -914,6 +904,8 @@ } public TypeBinding resolveType(BlockScope scope) { + if (scope.isInsideCondition) + this.bits |= ASTNode.IsInsideCondition; // for code gen, harm the restrictiveFlag if (this.actualReceiverType != null) { 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.49 diff -u -r1.49 Statement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java 22 Jul 2010 04:25:45 -0000 1.49 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java 30 Nov 2010 14:42:16 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -48,7 +49,7 @@ // } return false; } -public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo); +public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired); public static final int NOT_COMPLAINED = 0; public static final int COMPLAINED_FAKE_REACHABLE = 1; Index: compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java,v retrieving revision 1.79 diff -u -r1.79 SwitchStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java 12 Aug 2010 16:58:28 -0000 1.79 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java 30 Nov 2010 14:42:16 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -45,9 +47,12 @@ int preSwitchInitStateIndex = -1; int mergedInitStateIndex = -1; - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { try { - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); + boolean expressionValueRequired = this.caseCount != 0 || // case-less: subject to optimization + ((this.expression.constant == Constant.NotAConstant) // constant branching ... + && (this.expression.implicitConversion & TypeIds.UNBOXING) != 0); // ... which cannot throw NPE? + flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo, expressionValueRequired); if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { this.expression.checkNPE(currentScope, flowContext, flowInfo); } @@ -89,7 +94,7 @@ fallThroughState = FALLTHROUGH; // reset below if needed } if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { - caseInits = statement.analyseCode(this.scope, switchContext, caseInits); + caseInits = statement.analyseCode(this.scope, switchContext, caseInits, false); // analyse as statement => ignore value if (caseInits == FlowInfo.DEAD_END) { fallThroughState = ESCAPING; } @@ -162,7 +167,9 @@ codeStream.pop(); } } else { - valueRequired = this.expression.constant == Constant.NotAConstant || hasCases; + valueRequired = hasCases || + ((this.expression.constant == Constant.NotAConstant) + && (this.expression.implicitConversion & TypeIds.UNBOXING) != 0); // generate expression this.expression.generateCode(currentScope, codeStream, valueRequired); } @@ -267,7 +274,13 @@ public void resolve(BlockScope upperScope) { try { boolean isEnumSwitch = false; - TypeBinding expressionType = this.expression.resolveType(upperScope); + TypeBinding expressionType = null; + try { + upperScope.isInsideCondition = true; + expressionType = this.expression.resolveType(upperScope); + } finally { + upperScope.isInsideCondition = false; + } if (expressionType != null) { this.expression.computeConversion(upperScope, expressionType, expressionType); checkType: { Index: compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java,v retrieving revision 1.53 diff -u -r1.53 SynchronizedStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java 7 Mar 2009 01:08:07 -0000 1.53 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java 30 Nov 2010 14:42:16 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -40,11 +41,7 @@ this.sourceEnd = e; this.sourceStart = s; } - -public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { this.preSynchronizedInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); @@ -58,7 +55,8 @@ this.block.analyseCode( this.scope, new InsideSubRoutineFlowContext(flowContext, this), - this.expression.analyseCode(this.scope, flowContext, flowInfo)); + this.expression.analyseCode(this.scope, flowContext, flowInfo, true), // require expression value + false); // ignore value of statements this.mergedSynchronizedInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); Index: compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java,v retrieving revision 1.37 diff -u -r1.37 ThisReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java 7 Mar 2009 01:08:07 -0000 1.37 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java 30 Nov 2010 14:42:16 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -35,7 +36,7 @@ /* * @see Reference#analyseAssignment(...) */ - public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { + public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) { return flowInfo; // this cannot be assigned } Index: compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java,v retrieving revision 1.39 diff -u -r1.39 ThrowStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java 7 Mar 2009 01:08:07 -0000 1.39 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java 30 Nov 2010 14:42:17 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -30,8 +31,8 @@ this.sourceEnd = sourceEnd; } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - this.exception.analyseCode(currentScope, flowContext, flowInfo); +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + this.exception.analyseCode(currentScope, flowContext, flowInfo, true); // cannot optimize this.exception.checkNPE(currentScope, flowContext, flowInfo); // need to check that exception thrown is actually caught somewhere flowContext.checkExceptionHandlers(this.exceptionType, this, flowInfo, currentScope); Index: compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java,v retrieving revision 1.114 diff -u -r1.114 TryStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 19 Nov 2009 15:57:21 -0000 1.114 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 30 Nov 2010 14:42:19 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -61,7 +62,8 @@ int naturalExitMergeInitStateIndex = -1; int[] catchExitInitStateIndexes; -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { // Consider the try block and catch block so as to compute the intersection of initializations and // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its @@ -99,7 +101,7 @@ if (this.tryBlock.isEmptyBlock()) { tryInfo = flowInfo; } else { - tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); + tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy(), false); // statements, ignore values if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) this.bits |= ASTNode.IsTryBlockExiting; } @@ -151,11 +153,7 @@ if (this.tryBlock.statements == null) { catchInfo.setReachMode(FlowInfo.UNREACHABLE); } - catchInfo = - this.catchBlocks[i].analyseCode( - currentScope, - flowContext, - catchInfo); + catchInfo = this.catchBlocks[i].analyseCode(currentScope, flowContext, catchInfo, false); // statements, ignore values this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo); this.catchExits[i] = (catchInfo.tagBits & FlowInfo.UNREACHABLE) != 0; @@ -183,7 +181,8 @@ .analyseCode( currentScope, finallyContext = new FinallyFlowContext(flowContext, this.finallyBlock), - flowInfo.nullInfoLessUnconditionalCopy()) + flowInfo.nullInfoLessUnconditionalCopy(), + false) // statements, ignore values .unconditionalInits(); if (subInfo == FlowInfo.DEAD_END) { this.bits |= ASTNode.IsSubRoutineEscaping; @@ -208,7 +207,7 @@ if (this.tryBlock.isEmptyBlock()) { tryInfo = flowInfo; } else { - tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); + tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy(), false); // statements, ignore values if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) this.bits |= ASTNode.IsTryBlockExiting; } @@ -260,11 +259,7 @@ if (this.tryBlock.statements == null) { catchInfo.setReachMode(FlowInfo.UNREACHABLE); } - catchInfo = - this.catchBlocks[i].analyseCode( - currentScope, - insideSubContext, - catchInfo); + catchInfo = this.catchBlocks[i].analyseCode(currentScope, insideSubContext, catchInfo, false); // statements, ignore values this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo); this.catchExits[i] = (catchInfo.tagBits & FlowInfo.UNREACHABLE) != 0; 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.164 diff -u -r1.164 TypeDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java 21 Jun 2010 09:47:48 -0000 1.164 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java 30 Nov 2010 14:42:20 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -187,7 +188,7 @@ * Flow analysis for a local innertype * */ -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { if (this.ignoreFurtherInvestigation) return flowInfo; try { Index: compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java,v retrieving revision 1.44 diff -u -r1.44 TypeReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java 18 Mar 2010 16:22:38 -0000 1.44 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java 30 Nov 2010 14:42:21 -0000 @@ -7,12 +7,11 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; @@ -82,9 +81,6 @@ public void aboutToResolve(Scope scope) { // default implementation: do nothing } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return flowInfo; -} public void checkBounds(Scope scope) { // only parameterized type references have bounds } Index: compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java,v retrieving revision 1.55 diff -u -r1.55 UnaryExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java 6 Oct 2009 13:18:02 -0000 1.55 +++ compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java 30 Nov 2010 14:42:21 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -26,21 +27,21 @@ this.expression = expression; this.bits |= operator << OperatorSHIFT; // encode operator } - -public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - this.expression.checkNPE(currentScope, flowContext, flowInfo); - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { - return this.expression. - analyseCode(currentScope, flowContext, flowInfo). - asNegatedCondition(); - } else { - return this.expression. - analyseCode(currentScope, flowContext, flowInfo); + public FlowInfo analyseCode( + BlockScope currentScope, + FlowContext flowContext, + FlowInfo flowInfo, + boolean valueRequired) { + this.expression.checkNPE(currentScope, flowContext, flowInfo); + if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { + return this.expression. + analyseCode(currentScope, flowContext, flowInfo, valueRequired). + asNegatedCondition(); + } else { + return this.expression. + analyseCode(currentScope, flowContext, flowInfo, valueRequired); + } } -} public Constant optimizedBooleanConstant() { Index: compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java,v retrieving revision 1.66 diff -u -r1.66 WhileStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java 23 Aug 2010 08:41:25 -0000 1.66 +++ compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java 30 Nov 2010 14:42:21 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -37,7 +39,7 @@ this.sourceEnd = e; } - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { this.breakLabel = new BranchLabel(); this.continueLabel = new BranchLabel(); @@ -63,7 +65,8 @@ (condLoopContext = new LoopingFlowContext(flowContext, flowInfo, this, null, null, currentScope)), - condInfo); + condInfo, + !isConditionOptimizedFalse); // may optimize condition value if never entering the loop if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) { this.condition.checkNPE(currentScope, flowContext, flowInfo); } @@ -114,7 +117,7 @@ condInfo.initsWhenTrue()); if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { - actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo); + actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo, false); // statements, ignore values } // code generation can be optimized when no need to continue in the loop @@ -254,8 +257,13 @@ } public void resolve(BlockScope scope) { - - TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + TypeBinding type = null; + try { + scope.isInsideCondition = true; + type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + } finally { + scope.isInsideCondition = false; + } this.condition.computeConversion(scope, type, type); if (this.action != null) this.action.resolve(scope); 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.122 diff -u -r1.122 BlockScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 9 Nov 2010 19:59:19 -0000 1.122 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 30 Nov 2010 14:42:23 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -35,6 +36,8 @@ // record the current case statement being processed (for entire switch case block). public CaseStatement enclosingCase; // from 1.4 on, local types should not be accessed across switch case blocks (52221) + public boolean isInsideCondition = false; + public final static VariableBinding[] EmulationPathToImplicitThis = {}; public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {}; Index: compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java,v retrieving revision 1.48 diff -u -r1.48 LocalVariableBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java 22 Oct 2010 22:42:56 -0000 1.48 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java 30 Nov 2010 14:42:24 -0000 @@ -27,7 +27,7 @@ public static final int UNUSED = 0; public static final int USED = 1; public static final int FAKE_USED = 2; - public int useFlag; // for flow analysis (default is UNUSED), values < 0 indicate the number of compound uses (postIncrement or compoundAssignment) + public int useFlag; // for flow analysis (default is UNUSED) public BlockScope declaringScope; // back-pointer to its declaring scope public LocalDeclaration declaration; // for source-positions Index: compiler/org/eclipse/jdt/internal/compiler/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/messages.properties,v retrieving revision 1.12 diff -u -r1.12 messages.properties --- compiler/org/eclipse/jdt/internal/compiler/messages.properties 6 Oct 2009 01:01:20 -0000 1.12 +++ compiler/org/eclipse/jdt/internal/compiler/messages.properties 30 Nov 2010 14:41:46 -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 @@ -39,6 +39,7 @@ abort_missingCode = Missing code implementation in the compiler abort_againstSourceModel = Cannot compile against source model {0} issued from {1} abort_invalidOpcode = SANITY CHECK: Invalid opcode {0} at pc {1} for stackmap table attribute for method {2} +abort_unexpectedUnresolvedLocal=Unexpected unresolved local ### accept accept_cannot = Cannot accept the compilation unit: Index: compiler/org/eclipse/jdt/internal/compiler/util/Messages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Messages.java,v retrieving revision 1.15 diff -u -r1.15 Messages.java --- compiler/org/eclipse/jdt/internal/compiler/util/Messages.java 27 Jun 2008 16:04:05 -0000 1.15 +++ compiler/org/eclipse/jdt/internal/compiler/util/Messages.java 30 Nov 2010 14:42:24 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -113,6 +113,7 @@ public static String ast_missingCode; public static String constant_cannotCastedInto; public static String constant_cannotConvertedTo; + public static String abort_unexpectedUnresolvedLocal; static { initializeMessages(BUNDLE_NAME, Messages.class); Index: eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java,v retrieving revision 1.36 diff -u -r1.36 CodeSnippetReturnStatement.java --- eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java 5 Feb 2009 09:38:11 -0000 1.36 +++ eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java 30 Nov 2010 14:42:24 -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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.internal.eval; @@ -35,8 +36,8 @@ super(expr, s, e); } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - FlowInfo info = super.analyseCode(currentScope, flowContext, flowInfo); +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + FlowInfo info = super.analyseCode(currentScope, flowContext, flowInfo, valueRequired); // we need to remove this optimization in order to prevent the inlining of the return bytecode // 1GH0AU7: ITPJCORE:ALL - Eval - VerifyError in scrapbook page this.expression.bits &= ~IsReturnedValue; #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java,v retrieving revision 1.220 diff -u -r1.220 BatchCompilerTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 19 Nov 2010 14:21:58 -0000 1.220 +++ src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 30 Nov 2010 14:42:53 -0000 @@ -8,9 +8,11 @@ * Contributors: * IBM Corporation - initial API and implementation * Benjamin Muskalla - Contribution for bug 239066 - * Stephan Herrmann - Contribution for bug 236385 - * Stephan Herrmann - Contribution for bug 295551 - * Stephan Herrmann - Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann - Contributions for + * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used + * bug 295551 - Add option to automatically promote all warnings to errors + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -5950,13 +5952,18 @@ + " -warn:+null" + " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"", "", - "----------\n" + - "1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 4)\n" + - " if (o == null) {}\n" + - " ^\n" + - "Redundant null check: The variable o can only be null at this location\n" + - "----------\n" + - "1 problem (1 warning)", + "----------\n" + + "1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + + " Object o = null;\n" + + " ^\n" + + "The value of the local variable o is not used\n" + + "----------\n" + + "2. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 4)\n" + + " if (o == null) {}\n" + + " ^\n" + + "Redundant null check: The variable o can only be null at this location\n" + + "----------\n" + + "2 problems (2 warnings)", true); } // null ref option @@ -5979,7 +5986,13 @@ + " -warn:+nullDereference" + " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"", "", -"", +"----------\n" + +"1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + +" Object o = null;\n" + +" ^\n" + +"The value of the local variable o is not used\n" + +"----------\n" + +"1 problem (1 warning)", true); } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=190493 Index: src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java,v retrieving revision 1.46 diff -u -r1.46 FlowAnalysisTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 1 Sep 2010 15:49:30 -0000 1.46 +++ src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 30 Nov 2010 14:42:56 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 236385 + * Stephan Herrmann - Contributions for + * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -1836,12 +1838,17 @@ " ^^^^^\n" + "The type Local is never used locally\n" + "----------\n" + - "3. WARNING in X.java (at line 7)\n" + + "3. WARNING in X.java (at line 5)\n" + + " int i = 12;\n" + + " ^\n" + + "The value of the field Local.i is not used\n" + + "----------\n" + + "4. WARNING in X.java (at line 7)\n" + " void method() {\n" + " ^^^^^^^^\n" + "The method method() from the type Local is never used locally\n" + "----------\n" + - "4. ERROR in X.java (at line 11)\n" + + "5. ERROR in X.java (at line 11)\n" + " return;\n" + " ^^^^^^^\n" + "Unreachable code\n" + Index: src/org/eclipse/jdt/core/tests/compiler/regression/ForeachStatementTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ForeachStatementTest.java,v retrieving revision 1.47 diff -u -r1.47 ForeachStatementTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/ForeachStatementTest.java 9 Aug 2010 04:09:44 -0000 1.47 +++ src/org/eclipse/jdt/core/tests/compiler/regression/ForeachStatementTest.java 30 Nov 2010 14:43:00 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -1245,7 +1246,29 @@ " void test() {\n" + " for (Object object : array) {\n" + " String str = object.toString();\n" + - " str += \"\";\n" + // force 'str' to be preserved during codegen + " str += \"\";\n" + // try to force 'str' to be preserved during codegen (can still be optimized out) + " }\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X().test();\n" + + " System.out.println(\"SUCCESS\");\n" + + " }\n" + + "}\n", + }, + "SUCCESS"); +} +// 68440 - verify error due to local variable invalid slot sharing +public void test026a() { + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " Object[] array = {\n" + + " };\n" + + " void test() {\n" + + " for (Object object : array) {\n" + + " String str = object.toString();\n" + + " System.out.print(str);\n" + // really force 'str' to be preserved during codegen " }\n" + " }\n" + " public static void main(String[] args) {\n" + Index: src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java,v retrieving revision 1.29 diff -u -r1.29 ProgrammingProblemsTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java 9 Nov 2010 19:59:20 -0000 1.29 +++ src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java 30 Nov 2010 14:43:04 -0000 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann - Contributions for + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 328830 - [compiler] Variable should be marked unused when it can be optimized out *******************************************************************************/ package org.eclipse.jdt.core.tests.compiler.regression; @@ -2279,4 +2281,1119 @@ customOptions, null); } -} \ No newline at end of file +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SingleNameReference, local, postIncr, emptyThen +public void test0058() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR); + String content = + "public class X {\n" + + " public void method() {\n" + + " int a=10;\n" + + " if((a+=3) > 10) {\n" + // not counted as relevant use since bug 185682 + " }\n" + + " }\n" + + "}\n"; + this.runNegativeTest( + new String[] { + "X.java", content + }, + "----------\n" + + "1. ERROR in X.java (at line 3)\n" + + " int a=10;\n" + + " ^\n" + + "The value of the local variable a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING); + this.runConformTest( + new String[] { + "X.java", content + }, + "", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #6 ()V\n" + + " // Stack: 0, Locals: 1\n" + + " public void method();\n" + + " 0 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 6]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 1] local: this index: 0 type: X\n" + + "}"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SingleNameReference, field, postIncr, emptyThenWithElse +public void test0059() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR); + customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " private int a=10;\n" + + " public void method() {\n" + + " if(true || (a++ > 10 && false)) {\n" + // not counted as relevant use since bug 185682 + " System.out.println(\"OK\");\n" + + " } else {\n" + + " System.out.println(\"NOK\");\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " private int a=10;\n" + + " ^\n" + + "The value of the field X.a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// FieldReference, field, postIncr, optimizableCondition +public void test0060() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR); + customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " private int a=10;\n" + + " public void method() {\n" + + " if(this.a++ > 10 || true) {\n" + // not counted as relevant use since bug 185682 + " System.out.println(\"OK\");\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " private int a=10;\n" + + " ^\n" + + "The value of the field X.a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} + +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SingleNameReference, local, simpleRead, emptyThen +public void test0061() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public void method() {\n" + + " int a=10;\n" + + " if(a > 10) {\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 3)\n" + + " int a=10;\n" + + " ^\n" + + "The value of the local variable a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SingleNameReference, field, simpleRead, emptyThenWithElse +public void test0062() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR); + customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " private int a=10;\n" + + " public void method() {\n" + + " if(a > 10 && false) {\n" + + " } else {\n" + + " System.out.println(\"OK\");\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " private int a=10;\n" + + " ^\n" + + "The value of the field X.a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// FieldReference+QualifiedNameReference, field, simpleRead, optimizableCondition +public void test0063() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR); + customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " private int a=10;\n" + + " public void method(X other) {\n" + + " if(this.a < 3 || true) {\n" + + " System.out.println(\"OK\");\n" + + " }\n" + + " if(other.a > 10 || true) {\n" + + " System.out.println(\"OK\");\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " private int a=10;\n" + + " ^\n" + + "The value of the field X.a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// FieldReference+QualifiedNameReference, field, postIncr, optimizableCondition, exprOfForWhileDoSwitch +public void test0064() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR); + customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " private int a=10;\n" + + " public void method(X other) {\n" + + " for(;other.a++ > 10 && false;) {\n" + + " }\n" + + " while (true || this.a++>10) {\n" + + " }\n" + + " do {\n" + + " } while (this.a++>10 && false);\n" + + " switch(a++) {\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " private int a=10;\n" + + " ^\n" + + "The value of the field X.a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SingleNameReference, argument, simpleRead, optimizableCondition, exprOfForWhileDoSwitch +public void test0065() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.ERROR); + customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public void method(int a) {\n" + + " for(;a > 10 && false;) {\n" + + " }\n" + + " while (a>10 && false) {\n" + + " }\n" + + " do {\n" + + " } while (a>10 && false);\n" + + " switch(a) {\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " public void method(int a) {\n" + + " ^\n" + + "The value of the parameter a is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded signaled by AbortMethod +public void test0066() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR); + this.runConformTest( + new String[] { + "X.java", + "class X {\n" + + " int bar() { return 23; }\n" + + " void foo() {\n" + + " final int i=bar();\n" + + " new Runnable() {\n" + + " public void run() {\n" + + " if (i>3) { System.out.print(4); }\n" + // value is used + " }\n" + + " }.run();\n" + + " }\n" + + "}" + }, + "", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #6 ()V\n" + + " // Stack: 4, Locals: 2\n" + + " void foo();\n" + + " 0 aload_0 [this]\n" + + " 1 invokevirtual X.bar() : int [17]\n" + + " 4 istore_1 [i]\n" + + " 5 new X$1 [19]\n" + + " 8 dup\n" + + " 9 aload_0 [this]\n" + + " 10 iload_1 [i]\n" + + " 11 invokespecial X$1(X, int) [21]\n" + + " 14 invokevirtual X$1.run() : void [24]\n" + + " 17 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 4]\n" + + " [pc: 5, line: 5]\n" + + " [pc: 14, line: 9]\n" + + " [pc: 17, line: 10]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 18] local: this index: 0 type: X\n" + + " [pc: 5, pc: 18] local: i index: 1 type: int\n"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SimpleNameReference, localOfEnclosing, simpleRead, emptyThen +public void test0067() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "class X {\n" + + " int bar() { return 23; }\n" + + " void foo() {\n" + + " final int i=bar();\n" + + " new Runnable() {\n" + + " public void run() {\n" + + " if (i>3) { }\n" + // value is optimized out + " }\n" + + " }.run();\n" + + " }\n" + + "}" + }, + "----------\n" + + "1. WARNING in X.java (at line 4)\n" + + " final int i=bar();\n" + + " ^\n" + + "The value of the local variable i is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); + String expectedOutput = + " // Method descriptor #6 ()V\n" + + " // Stack: 3, Locals: 1\n" + + " void foo();\n" + + " 0 aload_0 [this]\n" + + " 1 invokevirtual X.bar() : int [17]\n" + + " 4 pop\n" + + " 5 new X$1 [19]\n" + + " 8 dup\n" + + " 9 aload_0 [this]\n" + + " 10 invokespecial X$1(X) [21]\n" + + " 13 invokevirtual X$1.run() : void [24]\n" + + " 16 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 4]\n" + + " [pc: 5, line: 5]\n" + + " [pc: 13, line: 9]\n" + + " [pc: 16, line: 10]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 17] local: this index: 0 type: X\n"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SingleNameReference, local, assignmentAsExpression, emptyThen +public void test0068() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public void method() {\n" + + " int a=10;\n" + + " int b;\n" + + " if((b=a) > 10) {\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 4)\n" + + " int b;\n" + + " ^\n" + + "The value of the local variable b is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); + String expectedOutput = + " // Method descriptor #6 ()V\n" + + " // Stack: 1, Locals: 2\n" + + " public void method();\n" + + " 0 bipush 10\n" + + " 2 istore_1 [a]\n" + + " 3 iload_1 [a]\n" + + " 4 pop\n" + + " 5 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 3]\n" + + " [pc: 3, line: 5]\n" + + " [pc: 5, line: 7]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 6] local: this index: 0 type: X\n" + + " [pc: 3, pc: 6] local: a index: 1 type: int\n"; // b has been optimized out + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type +public void test0069() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " int bar() { return 23; }\n" + + " void foo() {\n" + + " final int i=bar();\n" + + " new Runnable() {\n" + + " public void run() {\n" + + " if (i>3) {}\n" + // value is not used + " System.out.print(4);\n" + + " }\n" + + " }.run();\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X().foo();\n" + + " }\n" + + "}" + }, + "4", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #6 ()V\n" + + " // Stack: 3, Locals: 1\n" + + " void foo();\n" + + " 0 aload_0 [this]\n" + + " 1 invokevirtual X.bar() : int [17]\n" + + " 4 pop\n" + + " 5 new X$1 [19]\n" + + " 8 dup\n" + + " 9 aload_0 [this]\n" + + " 10 invokespecial X$1(X) [21]\n" + + " 13 invokevirtual X$1.run() : void [24]\n" + + " 16 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 4]\n" + + " [pc: 5, line: 5]\n" + + " [pc: 13, line: 10]\n" + + " [pc: 16, line: 11]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 17] local: this index: 0 type: X\n"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); + if (this.complianceLevel < ClassFileConstants.JDK1_4) { + expectedOutput = + " // Method descriptor #11 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [13]\n" + + " 4 aload_0 [this]\n" + + " 5 aload_1 [arg0]\n" + + " 6 putfield X$1.this$0 : X [16]\n" + + " 9 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 5]\n" + + " [pc: 4, line: 1]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n"; + } else if (this.complianceLevel < ClassFileConstants.JDK1_5) { + expectedOutput = + " // Method descriptor #11 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [13]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [15]\n" + + " 9 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n"; + } else { + expectedOutput = + " // Method descriptor #10 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [12]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [14]\n" + + " 9 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n"; + } + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type +public void test0070() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " int bar() { return 23; }\n" + + " public X() {\n" + + " final int i=bar();\n" + + " new Runnable() {\n" + + " public void run() {\n" + + " if (i>3) {}\n" + // value is not used + " System.out.print(4);\n" + + " }\n" + + " }.run();\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X();\n" + + " }\n" + + "}" + }, + "4", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #13 ()V\n" + + " // Stack: 3, Locals: 1\n" + + " public X();\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [14]\n" + + " 4 aload_0 [this]\n" + + " 5 invokevirtual X.bar() : int [16]\n" + + " 8 pop\n" + + " 9 new X$1 [18]\n" + + " 12 dup\n" + + " 13 aload_0 [this]\n" + + " 14 invokespecial X$1(X) [20]\n" + + " 17 invokevirtual X$1.run() : void [23]\n" + + " 20 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 3]\n" + + " [pc: 4, line: 4]\n" + + " [pc: 9, line: 5]\n" + + " [pc: 17, line: 10]\n" + + " [pc: 20, line: 11]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 21] local: this index: 0 type: X\n"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); + if (this.complianceLevel < ClassFileConstants.JDK1_4) { + expectedOutput = + " // Method descriptor #11 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [13]\n" + + " 4 aload_0 [this]\n" + + " 5 aload_1 [arg0]\n" + + " 6 putfield X$1.this$0 : X [16]\n" + + " 9 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 5]\n" + + " [pc: 4, line: 1]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n"; + } else if (this.complianceLevel < ClassFileConstants.JDK1_5) { + expectedOutput = + " // Method descriptor #11 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [13]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [15]\n" + + " 9 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n"; + } else { + expectedOutput = + " // Method descriptor #10 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [12]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [14]\n" + + " 9 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n"; + } + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type +public void test0071() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " int bar() { return 23; }\n" + + " X() {\n" + + " final int i=bar();\n" + + " new Runnable() {\n" + + " public void run() {\n" + + " if (i>3) { System.out.print(4); }\n" + // value is used + " }\n" + + " }.run();\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X();\n" + + " }\n" + + "}" + }, + "4", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #13 ()V\n" + + " // Stack: 4, Locals: 2\n" + + " X();\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [14]\n" + + " 4 aload_0 [this]\n" + + " 5 invokevirtual X.bar() : int [16]\n" + + " 8 istore_1 [i]\n" + + " 9 new X$1 [18]\n" + + " 12 dup\n" + + " 13 aload_0 [this]\n" + + " 14 iload_1 [i]\n" + + " 15 invokespecial X$1(X, int) [20]\n" + + " 18 invokevirtual X$1.run() : void [23]\n" + + " 21 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 3]\n" + + " [pc: 4, line: 4]\n" + + " [pc: 9, line: 5]\n" + + " [pc: 18, line: 9]\n" + + " [pc: 21, line: 10]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 22] local: this index: 0 type: X\n" + + " [pc: 9, pc: 22] local: i index: 1 type: int\n"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); + if (this.complianceLevel < ClassFileConstants.JDK1_4) { + expectedOutput = + " // Method descriptor #13 (LX;I)V\n" + + " // Stack: 2, Locals: 3\n" + + " X$1(X arg0, int arg1);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [15]\n" + + " 4 aload_0 [this]\n" + + " 5 aload_1 [arg0]\n" + + " 6 putfield X$1.this$0 : X [18]\n" + + " 9 aload_0 [this]\n" + + " 10 iload_2 [arg1]\n" + + " 11 putfield X$1.val$i : int [20]\n" + + " 14 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 5]\n" + + " [pc: 4, line: 1]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 15] local: this index: 0 type: new X(){}\n"; + } else if (this.complianceLevel < ClassFileConstants.JDK1_5) { + expectedOutput = + " // Method descriptor #13 (LX;I)V\n" + + " // Stack: 2, Locals: 3\n" + + " X$1(X arg0, int arg1);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [15]\n" + + " 5 aload_0 [this]\n" + + " 6 iload_2 [arg1]\n" + + " 7 putfield X$1.val$i : int [17]\n" + + " 10 aload_0 [this]\n" + + " 11 invokespecial java.lang.Object() [19]\n" + + " 14 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 10, line: 5]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 15] local: this index: 0 type: new X(){}\n"; + } else { + expectedOutput = + " // Method descriptor #12 (LX;I)V\n" + + " // Stack: 2, Locals: 3\n" + + " X$1(X arg0, int arg1);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [14]\n" + + " 5 aload_0 [this]\n" + + " 6 iload_2 [arg1]\n" + + " 7 putfield X$1.val$i : int [16]\n" + + " 10 aload_0 [this]\n" + + " 11 invokespecial java.lang.Object() [18]\n" + + " 14 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 10, line: 5]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 15] local: this index: 0 type: new X(){}\n"; + } + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type +public void test0072() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " int bar() { return 23; }\n" + + " X() {\n" + + " final int i=bar();\n" + + " new Runnable() {\n" + + " {\n" + + " if (i>3) { System.out.print(4); }\n" + // value is used + " }\n" + + " public void run() {\n" + + " }\n" + + " }.run();\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X();\n" + + " }\n" + + "}" + }, + "4", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #13 ()V\n" + + " // Stack: 4, Locals: 2\n" + + " X();\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [14]\n" + + " 4 aload_0 [this]\n" + + " 5 invokevirtual X.bar() : int [16]\n" + + " 8 istore_1 [i]\n" + + " 9 new X$1 [18]\n" + + " 12 dup\n" + + " 13 aload_0 [this]\n" + + " 14 iload_1 [i]\n" + + " 15 invokespecial X$1(X, int) [20]\n" + + " 18 invokevirtual X$1.run() : void [23]\n" + + " 21 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 3]\n" + + " [pc: 4, line: 4]\n" + + " [pc: 9, line: 5]\n" + + " [pc: 18, line: 11]\n" + + " [pc: 21, line: 12]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 22] local: this index: 0 type: X\n" + + " [pc: 9, pc: 22] local: i index: 1 type: int\n"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); + if (this.complianceLevel < ClassFileConstants.JDK1_4) { + expectedOutput = + " // Method descriptor #11 (LX;I)V\n" + + " // Stack: 2, Locals: 3\n" + + " X$1(X arg0, int arg1);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [13]\n" + + " 4 aload_0 [this]\n" + + " 5 aload_1 [arg0]\n" + + " 6 putfield X$1.this$0 : X [16]\n" + + " 9 iload_2 [arg1]\n" + + " 10 iconst_3\n" + + " 11 if_icmple 21\n" + + " 14 getstatic java.lang.System.out : java.io.PrintStream [18]\n" + + " 17 iconst_4\n" + + " 18 invokevirtual java.io.PrintStream.print(int) : void [24]\n" + + " 21 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 5]\n" + + " [pc: 9, line: 7]\n" + + " [pc: 21, line: 1]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 22] local: this index: 0 type: new X(){}\n"; + } else if (this.complianceLevel < ClassFileConstants.JDK1_5) { + expectedOutput = + " // Method descriptor #11 (LX;I)V\n" + + " // Stack: 2, Locals: 3\n" + + " X$1(X arg0, int arg1);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [13]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [15]\n" + + " 9 iload_2 [arg1]\n" + + " 10 iconst_3\n" + + " 11 if_icmple 21\n" + + " 14 getstatic java.lang.System.out : java.io.PrintStream [18]\n" + + " 17 iconst_4\n" + + " 18 invokevirtual java.io.PrintStream.print(int) : void [24]\n" + + " 21 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " [pc: 9, line: 7]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 22] local: this index: 0 type: new X(){}\n"; + } else { + expectedOutput = + " // Method descriptor #10 (LX;I)V\n" + + " // Stack: 2, Locals: 3\n" + + " X$1(X arg0, int arg1);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [12]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [14]\n" + + " 9 iload_2 [arg1]\n" + + " 10 iconst_3\n" + + " 11 if_icmple 21\n" + + " 14 getstatic java.lang.System.out : java.io.PrintStream [17]\n" + + " 17 iconst_4\n" + + " 18 invokevirtual java.io.PrintStream.print(int) : void [23]\n" + + " 21 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " [pc: 9, line: 7]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 22] local: this index: 0 type: new X(){}\n"; + } + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type +public void test0073() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " int bar() { return 23; }\n" + + " X() {\n" + + " final int i=bar();\n" + + " new Runnable() {\n" + + " {\n" + + " if (i>3) {}\n" + // value is not used + " System.out.print(4);\n" + + " }\n" + + " public void run() {\n" + + " }\n" + + " }.run();\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " new X();\n" + + " }\n" + + "}" + }, + "4", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #13 ()V\n" + + " // Stack: 3, Locals: 1\n" + + " X();\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [14]\n" + + " 4 aload_0 [this]\n" + + " 5 invokevirtual X.bar() : int [16]\n" + + " 8 pop\n" + + " 9 new X$1 [18]\n" + + " 12 dup\n" + + " 13 aload_0 [this]\n" + + " 14 invokespecial X$1(X) [20]\n" + + " 17 invokevirtual X$1.run() : void [23]\n" + + " 20 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 3]\n" + + " [pc: 4, line: 4]\n" + + " [pc: 9, line: 5]\n" + + " [pc: 17, line: 12]\n" + + " [pc: 20, line: 13]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 21] local: this index: 0 type: X\n"; + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); + if (this.complianceLevel < ClassFileConstants.JDK1_4) { + expectedOutput = + " // Method descriptor #11 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [13]\n" + + " 4 aload_0 [this]\n" + + " 5 aload_1 [arg0]\n" + + " 6 putfield X$1.this$0 : X [16]\n" + + " 9 getstatic java.lang.System.out : java.io.PrintStream [18]\n" + + " 12 iconst_4\n" + + " 13 invokevirtual java.io.PrintStream.print(int) : void [24]\n" + + " 16 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 5]\n" + + " [pc: 9, line: 8]\n" + + " [pc: 16, line: 1]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 17] local: this index: 0 type: new X(){}\n"; + } else if (this.complianceLevel < ClassFileConstants.JDK1_5) { + expectedOutput = + " // Method descriptor #11 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [13]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [15]\n" + + " 9 getstatic java.lang.System.out : java.io.PrintStream [18]\n" + + " 12 iconst_4\n" + + " 13 invokevirtual java.io.PrintStream.print(int) : void [24]\n" + + " 16 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " [pc: 9, line: 8]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 17] local: this index: 0 type: new X(){}\n"; + } else { + expectedOutput = + " // Method descriptor #10 (LX;)V\n" + + " // Stack: 2, Locals: 2\n" + + " X$1(X arg0);\n" + + " 0 aload_0 [this]\n" + + " 1 aload_1 [arg0]\n" + + " 2 putfield X$1.this$0 : X [12]\n" + + " 5 aload_0 [this]\n" + + " 6 invokespecial java.lang.Object() [14]\n" + + " 9 getstatic java.lang.System.out : java.io.PrintStream [17]\n" + + " 12 iconst_4\n" + + " 13 invokevirtual java.io.PrintStream.print(int) : void [23]\n" + + " 16 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 1]\n" + + " [pc: 5, line: 5]\n" + + " [pc: 9, line: 8]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 17] local: this index: 0 type: new X(){}\n"; + } + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// white box against an intermediate patch: testing that double analysis of a condition may harm +public void test0074() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING); + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " public void method() {\n" + + " int a=10;\n" + + " final int b;\n" + + " if((b=a) > 10) {\n" + + " System.out.print(3);\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 4)\n" + + " final int b;\n" + + " ^\n" + + "The value of the local variable b is not used\n" + + "----------\n", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + customOptions); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// postIncr inside array allocation: do generate +public void test0075() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " public int[] method() {\n" + + " int i = 0;\n" + + " if (new int[i++] == null) ;\n" + + " if (new int[]{i++} == null) ;\n" + + " return new int[++i];\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " System.out.print(new X().method().length);\n" + + " }\n" + + "}\n" + }, + "3", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// postIncr inside array allocation: optimize out +public void test0076() throws Exception { + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " public void method(int a) {\n" + + " int i = 0;\n" + + " if (new int[i+=a] == null) ;\n" + + " if (new int[]{i++} == null) ;\n" + + " }\n" + + "}\n" + }, + "", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #15 (I)V\n" + + " // Stack: 0, Locals: 2\n" + + " public void method(int a);\n" + + " 0 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 6]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 1] local: this index: 0 type: X\n" + + " [pc: 0, pc: 1] local: a index: 1 type: int\n" + + "}"; // i has been optimized out + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); +} +// https://bugs.eclipse.org/328830 - Variable should be marked unused when it can be optimized out +// postIncr inside array allocation: don't optimize out if unboxing may cause NPE +public void test0077() throws Exception { + if (this.complianceLevel < ClassFileConstants.JDK1_5) + return; // requires auto unboxing + Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR); + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " public void method(int a) {\n" + + " Integer i = null;\n" + + " if (new int[i++] == null) ;\n" + + " }\n" + + "}\n" + }, + "", + null/*classLibraries*/, + true/*shouldFlushOutputDirectory*/, + null, + customOptions, + null); + String expectedOutput = + " // Method descriptor #15 (I)V\n" + + " // Stack: 3, Locals: 3\n" + + " public void method(int a);\n" + + " 0 aconst_null\n" + + " 1 astore_2 [i]\n" + + " 2 aload_2 [i]\n" + + " 3 dup\n" + + " 4 invokevirtual java.lang.Integer.intValue() : int [16]\n" + + " 7 iconst_1\n" + + " 8 iadd\n" + + " 9 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [22]\n" + + " 12 astore_2 [i]\n" + + " 13 invokevirtual java.lang.Integer.intValue() : int [16]\n" + + " 16 pop\n" + + " 17 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 3]\n" + + " [pc: 2, line: 4]\n" + + " [pc: 17, line: 5]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 18] local: this index: 0 type: X\n" + + " [pc: 0, pc: 18] local: a index: 1 type: int\n" + + " [pc: 2, pc: 18] local: i index: 2 type: java.lang.Integer\n" + + "}"; // nothing has been optimized out + checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput); + } + +}