### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: batch/org/eclipse/jdt/internal/compiler/batch/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties,v retrieving revision 1.782 diff -u -r1.782 messages.properties --- batch/org/eclipse/jdt/internal/compiler/batch/messages.properties 25 Nov 2008 14:38:15 -0000 1.782 +++ batch/org/eclipse/jdt/internal/compiler/batch/messages.properties 26 Nov 2008 17:40:40 -0000 @@ -233,6 +233,7 @@ \ -warn: enable exactly the listed warnings\n\ \ -warn:+ enable additional warnings\n\ \ -warn:- disable specific warnings\n\ +\ allDeadCode dead code including trivial if(DEBUG) check\n\ \ allDeprecation deprecation including inside deprecated code\n\ \ allJavadoc invalid or missing javadoc\n\ \ assertIdentifier + ''assert'' used as identifier\n\ @@ -241,6 +242,7 @@ \ compareIdentical + comparing identical expressions\n\ \ conditionAssign possible accidental boolean assignment\n\ \ constructorName + method with constructor name\n\ +\ deadCode dead code excluding trivial if (DEBUG) check\n\ \ dep-ann missing @Deprecated annotation\n\ \ deprecation + deprecation outside deprecated code\n\ \ discouraged + use of types matching a discouraged access rule\n\ Index: batch/org/eclipse/jdt/internal/compiler/batch/Main.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java,v retrieving revision 1.337 diff -u -r1.337 Main.java --- batch/org/eclipse/jdt/internal/compiler/batch/Main.java 24 Nov 2008 13:13:44 -0000 1.337 +++ batch/org/eclipse/jdt/internal/compiler/batch/Main.java 26 Nov 2008 17:40:40 -0000 @@ -3084,6 +3084,14 @@ CompilerOptions.OPTION_ReportAssertIdentifier, isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE); return; + } else if (token.equals("allDeadCode")) { //$NON-NLS-1$ + this.options.put( + CompilerOptions.OPTION_ReportDeadCode, + isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE); + this.options.put( + CompilerOptions.OPTION_ReportDeadCodeInTrivialIfStatement, + isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); + return; } break; case 'b' : @@ -3143,6 +3151,9 @@ this.options.put( CompilerOptions.OPTION_ReportDeadCode, isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE); + this.options.put( + CompilerOptions.OPTION_ReportDeadCodeInTrivialIfStatement, + CompilerOptions.DISABLED); return; } break; 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.67 diff -u -r1.67 BinaryExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 12 Sep 2008 13:28:53 -0000 1.67 +++ compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java 26 Nov 2008 17:40:42 -0000 @@ -56,8 +56,7 @@ 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) { // keep implementation in sync with CombinedBinaryExpression#analyseCode if (this.resolvedType.id == TypeIds.T_JavaLangString) { return this.right.analyseCode( @@ -1855,7 +1854,7 @@ int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID]; - this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType); + this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType); this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType); this.bits |= operatorSignature & 0xF; switch (operatorSignature & 0xF) { // record the current ReturnTypeID 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.23 diff -u -r1.23 EmptyStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java 24 Nov 2008 13:13:43 -0000 1.23 +++ compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java 26 Nov 2008 17:40:42 -0000 @@ -30,7 +30,6 @@ // Report an error if necessary public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int complaintLevel) { - // before 1.4, empty statements are tolerated anywhere if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_4) { return complaintLevel; 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.61 diff -u -r1.61 IfStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java 24 Nov 2008 13:13:42 -0000 1.61 +++ compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java 26 Nov 2008 17:40:42 -0000 @@ -30,155 +30,138 @@ int elseInitStateIndex = -1; int mergedInitStateIndex = -1; - public IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd) { +public IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd) { + this.condition = condition; + this.thenStatement = thenStatement; + // remember useful empty statement + if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; +} - this.condition = condition; - this.thenStatement = thenStatement; - // remember useful empty statement - if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - } - - public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) { - - this.condition = condition; - this.thenStatement = thenStatement; - // remember useful empty statement - if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement; - this.elseStatement = elseStatement; - if (elseStatement instanceof IfStatement) elseStatement.bits |= IsElseIfStatement; - if (elseStatement instanceof EmptyStatement) elseStatement.bits |= IsUsefulEmptyStatement; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - } - - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // process the condition - FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo); - 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; +public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) { + this.condition = condition; + this.thenStatement = thenStatement; + // remember useful empty statement + if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement; + this.elseStatement = elseStatement; + if (elseStatement instanceof IfStatement) elseStatement.bits |= IsElseIfStatement; + if (elseStatement instanceof EmptyStatement) elseStatement.bits |= IsUsefulEmptyStatement; + this.sourceStart = sourceStart; + this.sourceEnd = sourceEnd; +} - // process the THEN part - FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue(); +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + // process the condition + FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo); + 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; + + // process the THEN part + FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue(); + if (isConditionOptimizedFalse) { + thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } + FlowInfo elseFlowInfo = conditionFlowInfo.initsWhenFalse(); + if (isConditionOptimizedTrue) { + elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } + if (this.thenStatement != null) { + // Save info for code gen + this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo); if (isConditionOptimizedFalse) { - thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); - } - FlowInfo elseFlowInfo = conditionFlowInfo.initsWhenFalse(); - if (isConditionOptimizedTrue) { - elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); - } - if (this.thenStatement != null) { - // Save info for code gen - this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo); - if (this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { - thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); + if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) { + this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, initialComplaintLevel); } } - // code gen: optimizing the jump around the ELSE part - if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) { - this.bits |= ASTNode.ThenExit; - } - - // process the ELSE part - if (this.elseStatement != null) { - // signal else clause unnecessarily nested, tolerate else-if code pattern - if (thenFlowInfo == FlowInfo.DEAD_END - && (this.bits & IsElseIfStatement) == 0 // else of an else-if - && !(this.elseStatement instanceof IfStatement)) { - currentScope.problemReporter().unnecessaryElse(this.elseStatement); - } - // Save info for code gen - this.elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo); - if (this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { - elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); + thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); + } + // code gen: optimizing the jump around the ELSE part + if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) { + this.bits |= ASTNode.ThenExit; + } + + // process the ELSE part + if (this.elseStatement != null) { + // signal else clause unnecessarily nested, tolerate else-if code pattern + if (thenFlowInfo == FlowInfo.DEAD_END + && (this.bits & IsElseIfStatement) == 0 // else of an else-if + && !(this.elseStatement instanceof IfStatement)) { + currentScope.problemReporter().unnecessaryElse(this.elseStatement); + } + // Save info for code gen + this.elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo); + if (isConditionOptimizedTrue) { + if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) { + this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, initialComplaintLevel); } } + elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); + } + // merge THEN & ELSE initializations + FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( + thenFlowInfo, + isConditionOptimizedTrue, + elseFlowInfo, + isConditionOptimizedFalse, + true /*if(true){ return; } fake-reachable(); */); + this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); + return mergedInfo; +} - // merge THEN & ELSE initializations - FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( - thenFlowInfo, - isConditionOptimizedTrue, - elseFlowInfo, - isConditionOptimizedFalse, - true /*if(true){ return; } fake-reachable(); */); - this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - - /** - * If code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - BranchLabel endifLabel = new BranchLabel(codeStream); - - // optimizing the then/else part code gen - Constant cst; - boolean hasThenPart = - !(((cst = this.condition.optimizedBooleanConstant()) != Constant.NotAConstant - && cst.booleanValue() == false) - || this.thenStatement == null - || this.thenStatement.isEmptyBlock()); - boolean hasElsePart = - !((cst != Constant.NotAConstant && cst.booleanValue() == true) - || this.elseStatement == null - || this.elseStatement.isEmptyBlock()); - if (hasThenPart) { - BranchLabel falseLabel = null; - // generate boolean condition - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - null, - hasElsePart ? (falseLabel = new BranchLabel(codeStream)) : endifLabel, - true/*cst == Constant.NotAConstant*/); - // May loose some local variable initializations : affecting the local variable attributes - if (this.thenInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex); - } - // generate then statement - this.thenStatement.generateCode(currentScope, codeStream); - // jump around the else statement - if (hasElsePart) { - if ((this.bits & ASTNode.ThenExit) == 0) { - this.thenStatement.branchChainTo(endifLabel); - int position = codeStream.position; - codeStream.goto_(endifLabel); - //goto is tagged as part of the thenAction block - codeStream.updateLastRecordedEndPC((this.thenStatement instanceof Block) ? ((Block) this.thenStatement).scope : currentScope, position); - // generate else statement - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.elseInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.elseInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.elseInitStateIndex); - } - if (falseLabel != null) falseLabel.place(); - this.elseStatement.generateCode(currentScope, codeStream); +/** + * If code generation + * + * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope + * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream) { + if ((this.bits & IsReachable) == 0) { + return; + } + int pc = codeStream.position; + BranchLabel endifLabel = new BranchLabel(codeStream); + + // optimizing the then/else part code gen + Constant cst; + boolean hasThenPart = + !(((cst = this.condition.optimizedBooleanConstant()) != Constant.NotAConstant + && cst.booleanValue() == false) + || this.thenStatement == null + || this.thenStatement.isEmptyBlock()); + boolean hasElsePart = + !((cst != Constant.NotAConstant && cst.booleanValue() == true) + || this.elseStatement == null + || this.elseStatement.isEmptyBlock()); + if (hasThenPart) { + BranchLabel falseLabel = null; + // generate boolean condition + this.condition.generateOptimizedBoolean( + currentScope, + codeStream, + null, + hasElsePart ? (falseLabel = new BranchLabel(codeStream)) : endifLabel, + true/*cst == Constant.NotAConstant*/); + // May loose some local variable initializations : affecting the local variable attributes + if (this.thenInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex); + } + // generate then statement + this.thenStatement.generateCode(currentScope, codeStream); + // jump around the else statement + if (hasElsePart) { + if ((this.bits & ASTNode.ThenExit) == 0) { + this.thenStatement.branchChainTo(endifLabel); + int position = codeStream.position; + codeStream.goto_(endifLabel); + //goto is tagged as part of the thenAction block + codeStream.updateLastRecordedEndPC((this.thenStatement instanceof Block) ? ((Block) this.thenStatement).scope : currentScope, position); + // generate else statement } - } else if (hasElsePart) { - // generate boolean condition - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - endifLabel, - null, - true/*cst == Constant.NotAConstant*/); - // generate else statement // May loose some local variable initializations : affecting the local variable attributes if (this.elseInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( @@ -186,58 +169,104 @@ this.elseInitStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.elseInitStateIndex); } + if (falseLabel != null) falseLabel.place(); this.elseStatement.generateCode(currentScope, codeStream); - } else { - // generate condition side-effects - this.condition.generateCode(currentScope, codeStream, false); - codeStream.recordPositionsFrom(pc, this.sourceStart); } + } else if (hasElsePart) { + // generate boolean condition + this.condition.generateOptimizedBoolean( + currentScope, + codeStream, + endifLabel, + null, + true/*cst == Constant.NotAConstant*/); + // generate else statement // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { + if (this.elseInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables( currentScope, - this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); + this.elseInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.elseInitStateIndex); } - endifLabel.place(); + this.elseStatement.generateCode(currentScope, codeStream); + } else { + // generate condition side-effects + this.condition.generateCode(currentScope, codeStream, false); codeStream.recordPositionsFrom(pc, this.sourceStart); } + // May loose some local variable initializations : affecting the local variable attributes + if (this.mergedInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables( + currentScope, + this.mergedInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); + } + endifLabel.place(); + codeStream.recordPositionsFrom(pc, this.sourceStart); +} - public StringBuffer printStatement(int indent, StringBuffer output) { +/** + * Answers true if the if is identified as a known coding pattern which + * should be tolerated by dead code analysis. + * e.g. if (DEBUG) print(); // no complaint + * Only invoked when overall condition is known to be optimizeable into false. + */ +public static boolean isKnowDeadCodePattern(Expression expression) { + // if (!DEBUG) print(); - tolerated + if (expression instanceof UnaryExpression) { + expression = ((UnaryExpression) expression).expression; + } + // if (DEBUG) print(); - tolerated + if (expression instanceof Reference) return true; + +// if (expression instanceof BinaryExpression) { +// BinaryExpression binary = (BinaryExpression) expression; +// switch ((binary.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT/* operator */) { +// case OperatorIds.AND_AND : +// case OperatorIds.OR_OR : +// break; +// default: +// // if (DEBUG_LEVEL > 0) print(); - tolerated +// if ((binary.left instanceof Reference) && binary.right.constant != Constant.NotAConstant) +// return true; +// // if (0 < DEBUG_LEVEL) print(); - tolerated +// if ((binary.right instanceof Reference) && binary.left.constant != Constant.NotAConstant) +// return true; +// } +// } + return false; +} - printIndent(indent, output).append("if ("); //$NON-NLS-1$ - this.condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$ - this.thenStatement.printStatement(indent + 2, output); - if (this.elseStatement != null) { - output.append('\n'); - printIndent(indent, output); - output.append("else\n"); //$NON-NLS-1$ - this.elseStatement.printStatement(indent + 2, output); - } - return output; +public StringBuffer printStatement(int indent, StringBuffer output) { + printIndent(indent, output).append("if ("); //$NON-NLS-1$ + this.condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$ + this.thenStatement.printStatement(indent + 2, output); + if (this.elseStatement != null) { + output.append('\n'); + printIndent(indent, output); + output.append("else\n"); //$NON-NLS-1$ + this.elseStatement.printStatement(indent + 2, output); } + return output; +} - public void resolve(BlockScope scope) { +public void resolve(BlockScope scope) { + TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + this.condition.computeConversion(scope, type, type); + if (this.thenStatement != null) + this.thenStatement.resolve(scope); + if (this.elseStatement != null) + this.elseStatement.resolve(scope); +} - TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); - this.condition.computeConversion(scope, type, type); +public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + this.condition.traverse(visitor, blockScope); if (this.thenStatement != null) - this.thenStatement.resolve(scope); + this.thenStatement.traverse(visitor, blockScope); if (this.elseStatement != null) - this.elseStatement.resolve(scope); - } - - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.condition.traverse(visitor, blockScope); - if (this.thenStatement != null) - this.thenStatement.traverse(visitor, blockScope); - if (this.elseStatement != null) - this.elseStatement.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); + this.elseStatement.traverse(visitor, blockScope); } + visitor.endVisit(this, blockScope); +} } Index: model/org/eclipse/jdt/core/JavaCore.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java,v retrieving revision 1.631 diff -u -r1.631 JavaCore.java --- model/org/eclipse/jdt/core/JavaCore.java 24 Nov 2008 13:13:43 -0000 1.631 +++ model/org/eclipse/jdt/core/JavaCore.java 26 Nov 2008 17:40:43 -0000 @@ -1013,6 +1013,19 @@ */ public static final String COMPILER_PB_DEAD_CODE = PLUGIN_ID + ".compiler.problem.deadCode"; //$NON-NLS-1$ /** + * Compiler option ID: Reporting Dead Code Inside Trivial If Statement. + *

When enabled, the compiler will signal presence of dead code inside trivial IF statement, e.g. if (DEBUG)..... + *

The severity of the problem is controlled with option {@link #COMPILER_PB_DEAD_CODE}. + *

+ *
Option id:
"org.eclipse.jdt.core.compiler.problem.deadCodeInTrivialIfStatement"
+ *
Possible values:
{ "enabled", "disabled" }
+ *
Default:
"disabled"
+ *
+ * @since 3.5 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_DEAD_CODE_IN_TRIVIAL_IF_STATEMENT = PLUGIN_ID + ".compiler.problem.deadCodeInTrivialIfStatement"; //$NON-NLS-1$ + /** * Compiler option ID: Reporting Incomplete Enum Switch. *

When enabled, the compiler will issue an error or a warning whenever * an enum constant has no corresponding case label in an enum switch Index: compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java,v retrieving revision 1.210 diff -u -r1.210 CompilerOptions.java --- compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 24 Nov 2008 13:13:42 -0000 1.210 +++ compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 26 Nov 2008 17:40:42 -0000 @@ -124,6 +124,7 @@ public static final String OPTION_ReportMissingSynchronizedOnInheritedMethod = "org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod"; //$NON-NLS-1$ public static final String OPTION_ReportMissingHashCodeMethod = "org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod"; //$NON-NLS-1$ public static final String OPTION_ReportDeadCode = "org.eclipse.jdt.core.compiler.problem.deadCode"; //$NON-NLS-1$ + public static final String OPTION_ReportDeadCodeInTrivialIfStatement = "org.eclipse.jdt.core.compiler.problem.deadCodeInTrivialIfStatement"; //$NON-NLS-1$ // Backward compatibility public static final String OPTION_ReportInvalidAnnotation = "org.eclipse.jdt.core.compiler.problem.invalidAnnotation"; //$NON-NLS-1$ @@ -292,6 +293,8 @@ public boolean reportUnusedDeclaredThrownExceptionExemptExceptionAndThrowable; /** Specify whether should report constructor/setter method parameter hiding */ public boolean reportSpecialParameterHidingField; + /** Specify whether trivial deadcode pattern is to be reported (e.g. if (DEBUG) ...) */ + public boolean reportDeadCodeInTrivialIfStatement; /** Master flag controlling whether doc comment should be processed */ public boolean docCommentSupport; /** Specify if invalid javadoc shall be reported */ @@ -354,6 +357,32 @@ }; /** + * Initializing the compiler options with defaults + */ + public CompilerOptions(){ + this(null); // use default options + } + + /** + * Initializing the compiler options with external settings + * @param settings + */ + public CompilerOptions(Map settings){ + resetDefaults(); + if (settings != null) { + set(settings); + } + } + + /** + * @deprecated used to preserve 3.1 and 3.2M4 compatibility of some Compiler constructors + */ + public CompilerOptions(Map settings, boolean parseLiteralExpressionsAsConstants){ + this(settings); + this.parseLiteralExpressionsAsConstants = parseLiteralExpressionsAsConstants; + } + + /** * Return the most specific option key controlling this irritant. Note that in some case, some irritant is controlled by * other master options (e.g. javadoc, deprecation, etc.). * This information is intended for grouping purpose (several problems governed by a rule) @@ -773,32 +802,6 @@ return null; } - /** - * Initializing the compiler options with defaults - */ - public CompilerOptions(){ - this(null); // use default options - } - - /** - * Initializing the compiler options with external settings - * @param settings - */ - public CompilerOptions(Map settings){ - resetDefaults(); - if (settings != null) { - set(settings); - } - } - - /** - * @deprecated used to preserve 3.1 and 3.2M4 compatibility of some Compiler constructors - */ - public CompilerOptions(Map settings, boolean parseLiteralExpressionsAsConstants){ - this(settings); - this.parseLiteralExpressionsAsConstants = parseLiteralExpressionsAsConstants; - } - public Map getMap() { Map optionsMap = new HashMap(30); @@ -899,6 +902,7 @@ optionsMap.put(OPTION_ReportMissingSynchronizedOnInheritedMethod, getSeverityString(MissingSynchronizedModifierInInheritedMethod)); optionsMap.put(OPTION_ReportMissingHashCodeMethod, getSeverityString(ShouldImplementHashcode)); optionsMap.put(OPTION_ReportDeadCode, getSeverityString(DeadCode)); + optionsMap.put(OPTION_ReportDeadCodeInTrivialIfStatement, this.reportDeadCodeInTrivialIfStatement ? ENABLED : DISABLED); return optionsMap; } @@ -1031,6 +1035,10 @@ // enable annotation processing by default only in batch mode this.processAnnotations = false; + + // dead code detection + this.reportDeadCodeInTrivialIfStatement = false; + } public void set(Map optionsMap) { @@ -1155,6 +1163,13 @@ this.reportSpecialParameterHidingField = false; } } + if ((optionValue = optionsMap.get(OPTION_ReportDeadCodeInTrivialIfStatement )) != null) { + if (ENABLED.equals(optionValue)) { + this.reportDeadCodeInTrivialIfStatement = true; + } else if (DISABLED.equals(optionValue)) { + this.reportDeadCodeInTrivialIfStatement = false; + } + } if ((optionValue = optionsMap.get(OPTION_MaxProblemPerUnit)) != null) { if (optionValue instanceof String) { String stringValue = (String) optionValue; @@ -1469,6 +1484,7 @@ buf.append("\n\t- missing synchronized on inherited method: ").append(getSeverityString(MissingSynchronizedModifierInInheritedMethod)); //$NON-NLS-1$ buf.append("\n\t- should implement hashCode() method: ").append(getSeverityString(ShouldImplementHashcode)); //$NON-NLS-1$ buf.append("\n\t- dead code: ").append(getSeverityString(DeadCode)); //$NON-NLS-1$ + buf.append("\n\t- dead code in trivial if statement: ").append(this.reportDeadCodeInTrivialIfStatement ? ENABLED : DISABLED); //$NON-NLS-1$ return buf.toString(); } #P org.eclipse.jdt.core.tests Index: Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/NegativeTest.java =================================================================== RCS file: /home/cvs/numbat/org.eclipse.jdt.core.tests/Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/NegativeTest.java,v retrieving revision 1.320 diff -u -r1.320 NegativeTest.java --- Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/NegativeTest.java 24 Nov 2008 13:13:50 -0000 1.320 +++ Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/NegativeTest.java 26 Nov 2008 17:40:50 -0000 @@ -11583,32 +11583,10 @@ " ^^^^^^^^\n" + "The method doTest() from the type Test is never used locally\n" + "----------\n" + - "2. WARNING in Test.java (at line 5)\n" + - " if (DEBUG){ \n" + - " time = System.currentTimeMillis(); \n" + - " } \n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "3. WARNING in Test.java (at line 9)\n" + - " if (DEBUG) { \n" + - " System.out.println(\"Bob takes: \" + (System.currentTimeMillis() - time) + \" ms\"); \n" + - " } \n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "4. WARNING in Test.java (at line 12)\n" + + "2. WARNING in Test.java (at line 12)\n" + " int i = 0; \n" + " ^\n" + "The local variable i is never read\n" + - "----------\n" + - "5. WARNING in Test.java (at line 13)\n" + - " if (DEBUG){ \n" + - " int j = 1; \n" + - " j++; \n" + - " } \n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + "----------\n", null, null, JavacTestOptions.Excuse.EclipseHasSomeMoreWarnings); } @@ -11736,87 +11714,74 @@ " ^^^^^^^^^^^\n" + "Dead code\n" + "----------\n" + - "2. WARNING in X.java (at line 18)\n" + - " if (FALSE) { \n" + - " doit(obj); \n" + - " } \n" + - " ^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "3. WARNING in X.java (at line 22)\n" + + "2. WARNING in X.java (at line 22)\n" + " if (false) { \n" + " doit(obj); \n" + " } \n" + " ^^^^^^^^^^^^^^^^^^^^^\n" + "Dead code\n" + "----------\n" + - "4. WARNING in X.java (at line 28)\n" + + "3. WARNING in X.java (at line 28)\n" + " Object obj = \"dummy\"; \n" + " ^^^\n" + "The local variable obj is never read\n" + "----------\n" + - "5. WARNING in X.java (at line 36)\n" + + "4. WARNING in X.java (at line 36)\n" + " if (false) { \n" + " doit(obj); //this is DEFINITELY unreachable code, but is not recognized as such \n" + " } \n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + "Dead code\n" + "----------\n" + - "6. WARNING in X.java (at line 40)\n" + - " if (FALSE) { \n" + - " doit(obj); //this is conditionnally unreachable code, but is not recognized as such \n" + - " } \n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "7. ERROR in X.java (at line 44)\n" + + "5. ERROR in X.java (at line 44)\n" + " while (false) { \n" + " doit(obj); //this is DEFINITELY unreachable code, and is recognized as such, with error \n" + " } \n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + "Unreachable code\n" + "----------\n" + - "8. ERROR in X.java (at line 48)\n" + + "6. ERROR in X.java (at line 48)\n" + " while (FALSE) { \n" + " doit(obj); //this is conditionnally unreachable code, but is recognized as definitely unreacheable code, with error \n" + " } \n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + "Unreachable code\n" + "----------\n" + - "9. ERROR in X.java (at line 52)\n" + + "7. ERROR in X.java (at line 52)\n" + " for (; false;) { \n" + " doit(obj); //this is DEFINITELY unreachable code, but is recognized as definitely unreacheable code, with error \n" + " } \n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + "Unreachable code\n" + "----------\n" + - "10. ERROR in X.java (at line 56)\n" + + "8. ERROR in X.java (at line 56)\n" + " for (; FALSE;) { \n" + " doit(obj); //this is conditionnally unreachable code, but is recognized as definitely unreacheable code, with error \n" + " } \n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + "Unreachable code\n" + "----------\n" + - "11. WARNING in X.java (at line 60)\n" + + "9. WARNING in X.java (at line 60)\n" + " int i = (false ? doit(\"0\") : doit(\"1\")); \n" + " ^^^^^^^^^\n" + "Dead code\n" + "----------\n" + - "12. WARNING in X.java (at line 63)\n" + + "10. WARNING in X.java (at line 63)\n" + " int j = (FALSE ? doit(\"0\") : doit(\"1\")); \n" + " ^^^^^^^^^\n" + "Dead code\n" + "----------\n" + - "13. WARNING in X.java (at line 77)\n" + + "11. WARNING in X.java (at line 77)\n" + " doit(obj); //this is conditionnally unreachable code \n" + " ^^^^^^^^^\n" + "Dead code\n" + "----------\n" + - "14. WARNING in X.java (at line 91)\n" + + "12. WARNING in X.java (at line 91)\n" + " doit(obj); //this is DEFINITELY unreachable code \n" + " ^^^^^^^^^\n" + "Dead code\n" + - "----------\n", + "----------\n" +, null, true, customOptions); #P org.eclipse.jdt.core.tests.compiler 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.36 diff -u -r1.36 FlowAnalysisTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 25 Nov 2008 12:27:18 -0000 1.36 +++ src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 26 Nov 2008 17:40:53 -0000 @@ -1471,16 +1471,7 @@ }, false /* expectingCompilerErrors */, "----------\n" + - "1. WARNING in X.java (at line 4)\n" + - " if (b) {\n" + - " label: while (bar()) {\n" + - " }\n" + - " return null;\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" + - "2. WARNING in X.java (at line 5)\n" + + "1. WARNING in X.java (at line 5)\n" + " label: while (bar()) {\n" + " ^^^^^\n" + "The label label is never explicitly referenced\n" + @@ -1518,16 +1509,7 @@ "}\n" }, false /* expectingCompilerErrors */, - "----------\n" + - "1. WARNING in X.java (at line 4)\n" + - " if (b) {\n" + - " while (bar()) {\n" + - " }\n" + - " return null;\n" + - " }\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Dead code\n" + - "----------\n" /* expectedCompilerLog */, + "" /* expectedCompilerLog */, "" /* expectedOutputString */, "" /* expectedErrorString */, false /* forceExecution */, @@ -1907,6 +1889,75 @@ "Unreachable code\n" + "----------\n"); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=48399 - variation +public void test060() { + runNegativeTest( + new String[] { /* test files */ + "X.java", + "public class X {\n" + + " static final boolean DEBUG = false;\n" + + " static final int DEBUG_LEVEL = 0;\n" + + " boolean check() { return true; }\n" + + " void foo(boolean b) {\n" + + " if (DEBUG)\n" + + " System.out.println(\"fake reachable1\"); //$NON-NLS-1$\n" + + " if (DEBUG && b)\n" + + " System.out.println(\"fake reachable2\"); //$NON-NLS-1$\n" + + " if (DEBUG && check())\n" + + " System.out.println(\"fake reachable3\"); //$NON-NLS-1$\n" + + " if (b && DEBUG)\n" + + " System.out.println(\"fake reachable4\"); //$NON-NLS-1$\n" + + " if (check() && DEBUG)\n" + + " System.out.println(\"fake reachable5\"); //$NON-NLS-1$\n" + + " if (DEBUG_LEVEL > 1) \n" + + " System.out.println(\"fake reachable6\"); //$NON-NLS-1$\n" + + " return;\n" + + " return;\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 8)\n" + + " if (DEBUG && b)\n" + + " ^\n" + + "Dead code\n" + + "----------\n" + + "2. WARNING in X.java (at line 9)\n" + + " System.out.println(\"fake reachable2\"); //$NON-NLS-1$\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "3. WARNING in X.java (at line 10)\n" + + " if (DEBUG && check())\n" + + " ^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "4. WARNING in X.java (at line 11)\n" + + " System.out.println(\"fake reachable3\"); //$NON-NLS-1$\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "5. WARNING in X.java (at line 13)\n" + + " System.out.println(\"fake reachable4\"); //$NON-NLS-1$\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "6. WARNING in X.java (at line 15)\n" + + " System.out.println(\"fake reachable5\"); //$NON-NLS-1$\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "7. WARNING in X.java (at line 17)\n" + + " System.out.println(\"fake reachable6\"); //$NON-NLS-1$\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "8. ERROR in X.java (at line 19)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Unreachable code\n" + + "----------\n"); +} public static Class testClass() { return FlowAnalysisTest.class; } 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.182 diff -u -r1.182 BatchCompilerTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 24 Nov 2008 13:14:04 -0000 1.182 +++ src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 26 Nov 2008 17:40:52 -0000 @@ -1636,6 +1636,7 @@ " -warn: enable exactly the listed warnings\n" + " -warn:+ enable additional warnings\n" + " -warn:- disable specific warnings\n" + + " allDeadCode dead code including trivial if(DEBUG) check\n" + " allDeprecation deprecation including inside deprecated code\n" + " allJavadoc invalid or missing javadoc\n" + " assertIdentifier + ''assert'' used as identifier\n" + @@ -1644,6 +1645,7 @@ " compareIdentical + comparing identical expressions\n" + " conditionAssign possible accidental boolean assignment\n" + " constructorName + method with constructor name\n" + + " deadCode dead code excluding trivial if (DEBUG) check\n" + " dep-ann missing @Deprecated annotation\n" + " deprecation + deprecation outside deprecated code\n" + " discouraged + use of types matching a discouraged access rule\n" + @@ -1777,6 +1779,7 @@ "