### Eclipse Workspace Patch 1.0 #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.34 diff -u -r1.34 FlowAnalysisTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 9 Sep 2008 16:39:25 -0000 1.34 +++ src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java 21 Nov 2008 10:20:13 -0000 @@ -34,6 +34,11 @@ return buildAllCompliancesTestSuite(testClass()); } +protected Map getCompilerOptions() { + Map map = super.getCompilerOptions(); + map.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.WARNING); + return map; +} public void test001() { this.runNegativeTest(new String[] { "X.java", // ================= @@ -48,11 +53,18 @@ " } \n" + "}\n", }, - "----------\n" + - "1. ERROR in X.java (at line 2)\n" + - " public String foo(int i) {\n" + - " ^^^^^^^^^^\n" + - "This method must return a result of type String\n" + + "----------\n" + + "1. ERROR in X.java (at line 2)\n" + + " public String foo(int i) {\n" + + " ^^^^^^^^^^\n" + + "This method must return a result of type String\n" + + "----------\n" + + "2. WARNING in X.java (at line 6)\n" + + " if (i > 0) {\n" + + " return null;\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + "----------\n"); } @@ -712,11 +724,16 @@ " }\n" + "}" }, - "----------\n" + - "1. ERROR in X.java (at line 10)\n" + - " x.foo();\n" + - " ^\n" + - "The local variable x may not have been initialized\n" + + "----------\n" + + "1. WARNING in X.java (at line 8)\n" + + " x = new X();\n" + + " ^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X.java (at line 10)\n" + + " x.foo();\n" + + " ^\n" + + "The local variable x may not have been initialized\n" + "----------\n", JavacTestOptions.JavacHasABug.JavacBugFixed_6_10); } @@ -1169,11 +1186,19 @@ " }\n" + "}" }, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " System.out.println(s);\n" + - " ^\n" + - "The local variable s may not have been initialized\n" + + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " if (false) {\n" + + " String s;\n" + + " System.out.println(s);\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X.java (at line 5)\n" + + " System.out.println(s);\n" + + " ^\n" + + "The local variable s may not have been initialized\n" + "----------\n"); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=166641 @@ -1210,11 +1235,21 @@ " }\n" + "}" }, - "----------\n" + - "1. ERROR in X.java (at line 6)\n" + - " System.out.println(s);\n" + - " ^\n" + - "The local variable s may not have been initialized\n" + + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " if (false) {\n" + + " String s;\n" + + " if (System.out != null) {\n" + + " System.out.println(s);\n" + + " }\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X.java (at line 6)\n" + + " System.out.println(s);\n" + + " ^\n" + + "The local variable s may not have been initialized\n" + "----------\n"); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=166641 @@ -1232,11 +1267,18 @@ " }\n" + "}" }, - "----------\n" + - "1. ERROR in X.java (at line 5)\n" + - " s = \"\";\n" + - " ^\n" + - "The final local variable s cannot be assigned. It must be blank and not using a compound assignment\n" + + "----------\n" + + "1. WARNING in X.java (at line 4)\n" + + " if (false) {\n" + + " s = \"\";\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X.java (at line 5)\n" + + " s = \"\";\n" + + " ^\n" + + "The final local variable s cannot be assigned. It must be blank and not using a compound assignment\n" + "----------\n"); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=166641 @@ -1273,11 +1315,18 @@ " }\n" + "}" }, - "----------\n" + - "1. ERROR in X.java (at line 7)\n" + - " s = \"\";\n" + - " ^\n" + - "The final local variable s may already have been assigned\n" + + "----------\n" + + "1. WARNING in X.java (at line 4)\n" + + " if (false) {\n" + + " s = \"\";\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X.java (at line 7)\n" + + " s = \"\";\n" + + " ^\n" + + "The final local variable s may already have been assigned\n" + "----------\n"); } // switch and definite assignment @@ -1421,11 +1470,20 @@ "}\n" }, false /* expectingCompilerErrors */, - "----------\n" + - "1. WARNING in X.java (at line 5)\n" + - " label: while (bar()) {\n" + - " ^^^^^\n" + - "The label label is never explicitly referenced\n" + + "----------\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" + + " label: while (bar()) {\n" + + " ^^^^^\n" + + "The label label is never explicitly referenced\n" + "----------\n" /* expectedCompilerLog */, "" /* expectedOutputString */, "" /* expectedErrorString */, @@ -1460,7 +1518,16 @@ "}\n" }, false /* expectingCompilerErrors */, - "" /* expectedCompilerLog */, + "----------\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 */, "" /* expectedOutputString */, "" /* expectedErrorString */, false /* forceExecution */, @@ -1506,6 +1573,200 @@ } ); } +public void test052() { + runNegativeTest( + new String[] { /* test files */ + "X.java", + "public class X {\n" + + " void foo(boolean b) {\n" + + " if (b && false) {\n" + + " int i = 0; // deadcode\n" + + " return; // 1\n" + + " }\n" + + " return;\n" + + " return;\n" + + " }\n" + + "} \n" + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " if (b && false) {\n" + + " int i = 0; // deadcode\n" + + " return; // 1\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X.java (at line 8)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Unreachable code\n" + + "----------\n"); +} +public void test053() { + runNegativeTest( + new String[] { /* test files */ + "X.java", + "public class X {\n" + + " void foo(boolean b) {\n" + + " if (false && b) {\n" + + " int j = 0; // deadcode\n" + + " return; // 2\n" + + " }\n" + + " return;\n" + + " return;\n" + + " }\n" + + "} \n" + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " if (false && b) {\n" + + " ^\n" + + "Dead code\n" + + "----------\n" + + "2. WARNING in X.java (at line 3)\n" + + " if (false && b) {\n" + + " int j = 0; // deadcode\n" + + " return; // 2\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "3. ERROR in X.java (at line 8)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Unreachable code\n" + + "----------\n"); +} +public void test054() { + runNegativeTest( + new String[] { /* test files */ + "X.java", + "public class X {\n" + + " void foo(boolean b) {\n" + + " while (true) {\n" + + " if (true) break;\n" + + " int k = 0; // deadcode\n" + + " }\n" + + " return;\n" + + " return;\n" + + " }\n" + + "} \n" + }, + "----------\n" + + "1. WARNING in X.java (at line 5)\n" + + " int k = 0; // deadcode\n" + + " ^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X.java (at line 8)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Unreachable code\n" + + "----------\n"); +} +public void test055() { + runNegativeTest( + new String[] { /* test files */ + "X.java", + "public class X {\n" + + " void foo(boolean b) {\n" + + " if (true || b) {\n" + + " int l = 0; // deadcode\n" + + " return; // 2a\n" + + " } \n" + + " return;\n" + + " return;\n" + + " }\n" + + "} \n" + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " if (true || b) {\n" + + " ^\n" + + "Dead code\n" + + "----------\n" + + "2. WARNING in X.java (at line 7)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "3. ERROR in X.java (at line 8)\n" + + " return;\n" + + " ^^^^^^^\n" + + "Unreachable code\n" + + "----------\n"); +} +public void test056() { + runNegativeTest( + new String[] { /* test files */ + "X.java", + "public class X {\n" + + " void bar() {\n" + + " return;\n" + + " {\n" + + " return; // 3\n" + + " }\n" + + " }\n" + + " void baz() {\n" + + " return;\n" + + " {\n" + + " }\n" + + " } \n" + + " void baz2() {\n" + + " return;\n" + + " ; // 4\n" + + " } \n" + + "} \n" + }, + "----------\n" + + "1. ERROR in X.java (at line 4)\n" + + " {\n" + + " return; // 3\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^\n" + + "Unreachable code\n" + + "----------\n" + + "2. ERROR in X.java (at line 10)\n" + + " {\n" + + " }\n" + + " ^^^^^\n" + + "Unreachable code\n" + + "----------\n"); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=110544 +public void test057() { + runNegativeTest( + new String[] { /* test files */ + "X.java", + "public class X {\n" + + " void foo(int x, int[] array) {\n" + + " for (int i = 0; \n" + + " i < array.length; \n" + + " i++) {//dead code\n" + + " if (x == array[i])\n" + + " return;\n" + + " else\n" + + " break;\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 4)\n" + + " {\n" + + " return; // 3\n" + + " }\n" + + " ^^^^^^^^^^^^^^^^^^^^^\n" + + "Unreachable code\n" + + "----------\n" + + "2. ERROR in X.java (at line 10)\n" + + " {\n" + + " }\n" + + " ^^^^^\n" + + "Unreachable code\n" + + "----------\n"); +} public static Class testClass() { return FlowAnalysisTest.class; } #P org.eclipse.jdt.core 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.98 diff -u -r1.98 ConstructorDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java 2 Oct 2008 00:46:27 -0000 1.98 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java 21 Nov 2008 10:20:15 -0000 @@ -125,13 +125,11 @@ // propagate to statements if (this.statements != null) { - boolean didAlreadyComplain = false; + int complaintLevel = Statement.NOT_COMPLAINED; for (int i = 0, count = this.statements.length; i < count; i++) { Statement stat = this.statements[i]; - if (!stat.complainIfUnreachable(flowInfo, this.scope, didAlreadyComplain)) { + if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo); - } else { - didAlreadyComplain = true; } } } 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.56 diff -u -r1.56 AssertStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java 25 Sep 2008 23:10:29 -0000 1.56 +++ compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java 21 Nov 2008 10:20:15 -0000 @@ -60,7 +60,10 @@ unconditionalInits(); UnconditionalFlowInfo assertInfo = assertRawInfo.unconditionalCopy(); if (isOptimizedTrueAssertion) { - assertInfo.setReachMode(FlowInfo.UNREACHABLE); + if ((assertInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) { + currentScope.problemReporter().fakeReachable(this.assertExpression); + assertInfo.setReachMode(FlowInfo.UNREACHABLE); + } } if (this.exceptionArgument != null) { 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.39 diff -u -r1.39 Block.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Block.java 27 Jun 2008 16:03:54 -0000 1.39 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Block.java 21 Nov 2008 10:20:15 -0000 @@ -22,121 +22,105 @@ // the number of explicit declaration , used to create scope public BlockScope scope; - public Block(int explicitDeclarations) { - this.explicitDeclarations = explicitDeclarations; - } - - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - // empty block - if (this.statements == null) return flowInfo; - boolean didAlreadyComplain = false; - for (int i = 0, max = this.statements.length; i < max; i++) { - Statement stat = this.statements[i]; - if (!stat.complainIfUnreachable(flowInfo, this.scope, didAlreadyComplain)) { - flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo); - } else { - didAlreadyComplain = true; - } - } - return flowInfo; - } - /** - * Code generation for a block - */ - public void generateCode(BlockScope currentScope, CodeStream codeStream) { +public Block(int explicitDeclarations) { + this.explicitDeclarations = explicitDeclarations; +} - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - if (this.statements != null) { - for (int i = 0, max = this.statements.length; i < max; i++) { - this.statements[i].generateCode(this.scope, codeStream); - } - } // for local variable debug attributes - if (this.scope != currentScope) { // was really associated with its own scope - codeStream.exitUserScope(this.scope); +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + // 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); } - codeStream.recordPositionsFrom(pc, this.sourceStart); } - - public boolean isEmptyBlock() { - - return this.statements == null; + return flowInfo; +} +/** + * Code generation for a block + */ +public void generateCode(BlockScope currentScope, CodeStream codeStream) { + if ((this.bits & IsReachable) == 0) { + return; } - - public StringBuffer printBody(int indent, StringBuffer output) { - - if (this.statements == null) return output; - for (int i = 0; i < this.statements.length; i++) { - this.statements[i].printStatement(indent + 1, output); - output.append('\n'); + int pc = codeStream.position; + if (this.statements != null) { + for (int i = 0, max = this.statements.length; i < max; i++) { + this.statements[i].generateCode(this.scope, codeStream); } - return output; + } // for local variable debug attributes + if (this.scope != currentScope) { // was really associated with its own scope + codeStream.exitUserScope(this.scope); } + codeStream.recordPositionsFrom(pc, this.sourceStart); +} - public StringBuffer printStatement(int indent, StringBuffer output) { +public boolean isEmptyBlock() { + return this.statements == null; +} - printIndent(indent, output); - output.append("{\n"); //$NON-NLS-1$ - printBody(indent, output); - return printIndent(indent, output).append('}'); +public StringBuffer printBody(int indent, StringBuffer output) { + if (this.statements == null) return output; + for (int i = 0; i < this.statements.length; i++) { + this.statements[i].printStatement(indent + 1, output); + output.append('\n'); } + return output; +} - public void resolve(BlockScope upperScope) { +public StringBuffer printStatement(int indent, StringBuffer output) { + printIndent(indent, output); + output.append("{\n"); //$NON-NLS-1$ + printBody(indent, output); + return printIndent(indent, output).append('}'); +} - if ((this.bits & UndocumentedEmptyBlock) != 0) { - upperScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); - } - if (this.statements != null) { - this.scope = - this.explicitDeclarations == 0 - ? upperScope - : new BlockScope(upperScope, this.explicitDeclarations); - for (int i = 0, length = this.statements.length; i < length; i++) { - this.statements[i].resolve(this.scope); - } +public void resolve(BlockScope upperScope) { + if ((this.bits & UndocumentedEmptyBlock) != 0) { + upperScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); + } + if (this.statements != null) { + this.scope = + this.explicitDeclarations == 0 + ? upperScope + : new BlockScope(upperScope, this.explicitDeclarations); + for (int i = 0, length = this.statements.length; i < length; i++) { + this.statements[i].resolve(this.scope); } } +} - public void resolveUsing(BlockScope givenScope) { - - if ((this.bits & UndocumentedEmptyBlock) != 0) { - givenScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); - } - // this optimized resolve(...) is sent only on none empty blocks - this.scope = givenScope; - if (this.statements != null) { - for (int i = 0, length = this.statements.length; i < length; i++) { - this.statements[i].resolve(this.scope); - } +public void resolveUsing(BlockScope givenScope) { + if ((this.bits & UndocumentedEmptyBlock) != 0) { + givenScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); + } + // this optimized resolve(...) is sent only on none empty blocks + this.scope = givenScope; + if (this.statements != null) { + for (int i = 0, length = this.statements.length; i < length; i++) { + this.statements[i].resolve(this.scope); } } +} - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - if (this.statements != null) { - for (int i = 0, length = this.statements.length; i < length; i++) - this.statements[i].traverse(visitor, this.scope); - } +public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + if (this.statements != null) { + for (int i = 0, length = this.statements.length; i < length; i++) + this.statements[i].traverse(visitor, this.scope); } - visitor.endVisit(this, blockScope); - } - - /** - * Dispatch the call on its last statement. - */ - public void branchChainTo(BranchLabel label) { - if (this.statements != null) { - this.statements[this.statements.length - 1].branchChainTo(label); - } } + visitor.endVisit(this, blockScope); +} +/** + * Dispatch the call on its last statement. + */ +public void branchChainTo(BranchLabel label) { + if (this.statements != null) { + this.statements[this.statements.length - 1].branchChainTo(label); + } +} } 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.22 diff -u -r1.22 EmptyStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java 27 Jun 2008 16:03:56 -0000 1.22 +++ compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java 21 Nov 2008 10:20:15 -0000 @@ -29,13 +29,13 @@ } // Report an error if necessary - public boolean complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) { + 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 false; + return complaintLevel; } - return super.complainIfUnreachable(flowInfo, scope, didAlreadyComplain); + return super.complainIfUnreachable(flowInfo, scope, complaintLevel); } public void generateCode(BlockScope currentScope, CodeStream codeStream){ 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.60 diff -u -r1.60 IfStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java 27 Jun 2008 16:03:55 -0000 1.60 +++ compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java 21 Nov 2008 10:20:16 -0000 @@ -53,14 +53,10 @@ this.sourceEnd = sourceEnd; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // process the condition - FlowInfo conditionFlowInfo = - this.condition.analyseCode(currentScope, flowContext, flowInfo); + 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; @@ -77,11 +73,9 @@ } if (this.thenStatement != null) { // Save info for code gen - this.thenInitStateIndex = - currentScope.methodScope().recordInitializationStates(thenFlowInfo); - if (!this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, false)) { - thenFlowInfo = - this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); + this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo); + if (this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { + thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); } } // code gen: optimizing the jump around the ELSE part @@ -98,11 +92,9 @@ currentScope.problemReporter().unnecessaryElse(this.elseStatement); } // Save info for code gen - this.elseInitStateIndex = - currentScope.methodScope().recordInitializationStates(elseFlowInfo); - if (!this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, false)) { - elseFlowInfo = - this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); + this.elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo); + if (this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { + elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); } } 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.90 diff -u -r1.90 ConditionalExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java 25 Sep 2008 23:10:29 -0000 1.90 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java 21 Nov 2008 10:20:15 -0000 @@ -52,7 +52,10 @@ // process the if-true part FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy(); if (isConditionOptimizedFalse) { - trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + if ((trueFlowInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) { + currentScope.problemReporter().fakeReachable(this.valueIfTrue); + trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } } this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo); trueFlowInfo = this.valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo); @@ -60,7 +63,10 @@ // process the if-false part FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy(); if (isConditionOptimizedTrue) { - falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + if ((falseFlowInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) { + currentScope.problemReporter().fakeReachable(this.valueIfFalse); + falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); + } } this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo); falseFlowInfo = this.valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo); @@ -85,11 +91,18 @@ UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().unconditionalCopy(); UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().unconditionalInits(); UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().unconditionalInits(); - if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); - if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); - if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); - if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); - + if (isValueIfTrueOptimizedFalse) { + trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); + } + if (isValueIfFalseOptimizedFalse) { + falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); + } + if (isValueIfTrueOptimizedTrue) { + trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); + } + if (isValueIfFalseOptimizedTrue) { + falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); + } mergedInfo = FlowInfo.conditional( trueInfoWhenTrue.mergedWith(falseInfoWhenTrue), 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.67 diff -u -r1.67 MethodDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 12 Sep 2008 13:31:45 -0000 1.67 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 21 Nov 2008 10:20:16 -0000 @@ -83,13 +83,11 @@ } // propagate to statements if (this.statements != null) { - boolean didAlreadyComplain = false; + int complaintLevel = Statement.NOT_COMPLAINED; for (int i = 0, count = this.statements.length; i < count; i++) { Statement stat = this.statements[i]; - if (!stat.complainIfUnreachable(flowInfo, this.scope, didAlreadyComplain)) { + if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo); - } else { - didAlreadyComplain = true; } } } 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.64 diff -u -r1.64 ForStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java 27 Jun 2008 16:03:56 -0000 1.64 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java 21 Nov 2008 10:20:16 -0000 @@ -58,13 +58,10 @@ } } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { this.breakLabel = new BranchLabel(); this.continueLabel = new BranchLabel(); + int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; // process the initializations if (this.initializations != null) { @@ -82,7 +79,7 @@ cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); boolean isConditionOptimizedTrue = cst == null || (cst != Constant.NotAConstant && cst.booleanValue() == true); boolean isConditionOptimizedFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false); - + // process the condition LoopingFlowContext condLoopContext = null; FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy(); @@ -137,9 +134,8 @@ actionInfo.setReachMode(FlowInfo.UNREACHABLE); } } - if (!this.action.complainIfUnreachable(actionInfo, this.scope, false)) { - actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo). - unconditionalInits(); + if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { + actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits(); } // code generation can be optimized when no need to continue in the loop @@ -179,9 +175,13 @@ } exitBranch.addPotentialInitializationsFrom(actionInfo). addInitializationsFrom(condInfo.initsWhenFalse()); - } - else { + } else { exitBranch.addInitializationsFrom(condInfo.initsWhenFalse()); + if (this.increments != null) { + if (initialComplaintLevel == Statement.NOT_COMPLAINED) { + currentScope.problemReporter().fakeReachable(this.increments[0]); + } + } } // nulls checks if (condLoopContext != null) { 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.61 diff -u -r1.61 WhileStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java 27 Jun 2008 16:03:54 -0000 1.61 +++ compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java 21 Nov 2008 10:20:16 -0000 @@ -36,13 +36,11 @@ this.sourceEnd = e; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { this.breakLabel = new BranchLabel(); this.continueLabel = new BranchLabel(); + int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; Constant cst = this.condition.constant; boolean isConditionTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; @@ -52,10 +50,10 @@ boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - this.preCondInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); + this.preCondInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); LoopingFlowContext condLoopContext; FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy(); + // we need to collect the contribution to nulls of the coming paths through the // loop, be they falling through normally or branched to break, continue labels // or catch blocks @@ -111,7 +109,7 @@ currentScope.methodScope().recordInitializationStates( condInfo.initsWhenTrue()); - if (!this.action.complainIfUnreachable(actionInfo, currentScope, false)) { + if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo); } 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.40 diff -u -r1.40 AND_AND_Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java 27 Jun 2008 16:03:56 -0000 1.40 +++ compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java 21 Nov 2008 10:20:15 -0000 @@ -54,7 +54,10 @@ int previousMode = rightInfo.reachMode(); if (isLeftOptimizedFalse) { - rightInfo.setReachMode(FlowInfo.UNREACHABLE); + if ((rightInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) { + currentScope.problemReporter().fakeReachable(this.right); + rightInfo.setReachMode(FlowInfo.UNREACHABLE); + } } rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo); FlowInfo mergedInfo = FlowInfo.conditional( 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.74 diff -u -r1.74 SwitchStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java 17 Sep 2008 09:08:38 -0000 1.74 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java 21 Nov 2008 10:20:16 -0000 @@ -44,11 +44,7 @@ int preSwitchInitStateIndex = -1; int mergedInitStateIndex = -1; - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { try { flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); SwitchFlowContext switchContext = @@ -58,11 +54,11 @@ // to the entry point) FlowInfo caseInits = FlowInfo.DEAD_END; // in case of statements before the first case - this.preSwitchInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); + this.preSwitchInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); int caseIndex = 0; if (this.statements != null) { - boolean didAlreadyComplain = false; + int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; + int complaintLevel = initialComplaintLevel; int fallThroughState = CASE; for (int i = 0, max = this.statements.length; i < max; i++) { Statement statement = this.statements[i]; @@ -74,7 +70,7 @@ this.scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase); } caseInits = caseInits.mergedWith(flowInfo.unconditionalInits()); - didAlreadyComplain = false; // reset complaint + complaintLevel = initialComplaintLevel; // reset complaint fallThroughState = CASE; } else if (statement == this.defaultCase) { // statement is the default case this.scope.enclosingCase = this.defaultCase; // record entering in a switch case block @@ -83,18 +79,16 @@ this.scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase); } caseInits = caseInits.mergedWith(flowInfo.unconditionalInits()); - didAlreadyComplain = false; // reset complaint + complaintLevel = initialComplaintLevel; // reset complaint fallThroughState = CASE; } else { fallThroughState = FALLTHROUGH; // reset below if needed } - if (!statement.complainIfUnreachable(caseInits, this.scope, didAlreadyComplain)) { + if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { caseInits = statement.analyseCode(this.scope, switchContext, caseInits); if (caseInits == FlowInfo.DEAD_END) { fallThroughState = ESCAPING; } - } else { - didAlreadyComplain = true; } } } @@ -107,10 +101,8 @@ // if no default case, then record it may jump over the block directly to the end if (this.defaultCase == null) { // only retain the potential initializations - flowInfo.addPotentialInitializationsFrom( - caseInits.mergedWith(switchContext.initsOnBreak)); - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); + flowInfo.addPotentialInitializationsFrom(caseInits.mergedWith(switchContext.initsOnBreak)); + this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); return flowInfo; } 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.42 diff -u -r1.42 Statement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java 27 Jun 2008 16:03:56 -0000 1.42 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java 21 Nov 2008 10:20:16 -0000 @@ -17,128 +17,136 @@ public abstract class Statement extends ASTNode { - public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo); +public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo); - /** - * INTERNAL USE ONLY. - * This is used to redirect inter-statements jumps. - */ - public void branchChainTo(BranchLabel label) { - // do nothing by default - } - - // Report an error if necessary - public boolean complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) { + public static final int NOT_COMPLAINED = 0; + public static final int COMPLAINED_FAKE_REACHABLE = 1; + public static final int COMPLAINED_UNREACHABLE = 2; + +/** + * INTERNAL USE ONLY. + * This is used to redirect inter-statements jumps. + */ +public void branchChainTo(BranchLabel label) { + // do nothing by default +} - if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) { - this.bits &= ~ASTNode.IsReachable; - boolean reported = flowInfo == FlowInfo.DEAD_END; - if (!didAlreadyComplain && reported) { +// Report an error if necessary (if even more unreachable than previously reported +// complaintLevel = 0 if was reachable up until now, 1 if fake reachable (deadcode), 2 if fatal unreachable (error) +public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previousComplaintLevel) { + if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) { + this.bits &= ~ASTNode.IsReachable; + if (flowInfo == FlowInfo.DEAD_END) { + if (previousComplaintLevel < COMPLAINED_UNREACHABLE) { scope.problemReporter().unreachableCode(this); } - return reported; // keep going for fake reachable + return COMPLAINED_UNREACHABLE; + } else { + if (previousComplaintLevel < COMPLAINED_FAKE_REACHABLE) { + scope.problemReporter().fakeReachable(this); + } + return COMPLAINED_FAKE_REACHABLE; } - return false; } + return previousComplaintLevel; +} - /** - * Generate invocation arguments, considering varargs methods - */ - public void generateArguments(MethodBinding binding, Expression[] arguments, BlockScope currentScope, CodeStream codeStream) { - - if (binding.isVarargs()) { - // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) : - // foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2}) - TypeBinding[] params = binding.parameters; - int paramLength = params.length; - int varArgIndex = paramLength - 1; - for (int i = 0; i < varArgIndex; i++) { +/** + * Generate invocation arguments, considering varargs methods + */ +public void generateArguments(MethodBinding binding, Expression[] arguments, BlockScope currentScope, CodeStream codeStream) { + if (binding.isVarargs()) { + // 5 possibilities exist for a call to the vararg method foo(int i, int ... value) : + // foo(1), foo(1, null), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new int[] {1, 2}) + TypeBinding[] params = binding.parameters; + int paramLength = params.length; + int varArgIndex = paramLength - 1; + for (int i = 0; i < varArgIndex; i++) { + arguments[i].generateCode(currentScope, codeStream, true); + } + + ArrayBinding varArgsType = (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type + ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure(); + int elementsTypeID = varArgsType.elementsType().id; + int argLength = arguments == null ? 0 : arguments.length; + + if (argLength > paramLength) { + // right number but not directly compatible or too many arguments - wrap extra into array + // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4) + // need to gen elements into an array, then gen each remaining element into created array + codeStream.generateInlinedValue(argLength - varArgIndex); + codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array + for (int i = varArgIndex; i < argLength; i++) { + codeStream.dup(); + codeStream.generateInlinedValue(i - varArgIndex); arguments[i].generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); } - - ArrayBinding varArgsType = (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type - ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure(); - int elementsTypeID = varArgsType.elementsType().id; - int argLength = arguments == null ? 0 : arguments.length; - - if (argLength > paramLength) { + } else if (argLength == paramLength) { + // right number of arguments - could be inexact - pass argument as is + TypeBinding lastType = arguments[varArgIndex].resolvedType; + if (lastType == TypeBinding.NULL + || (varArgsType.dimensions() == lastType.dimensions() + && lastType.isCompatibleWith(varArgsType))) { + // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is + arguments[varArgIndex].generateCode(currentScope, codeStream, true); + } else { // right number but not directly compatible or too many arguments - wrap extra into array - // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4) // need to gen elements into an array, then gen each remaining element into created array - codeStream.generateInlinedValue(argLength - varArgIndex); + codeStream.generateInlinedValue(1); codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array - for (int i = varArgIndex; i < argLength; i++) { - codeStream.dup(); - codeStream.generateInlinedValue(i - varArgIndex); - arguments[i].generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - } else if (argLength == paramLength) { - // right number of arguments - could be inexact - pass argument as is - TypeBinding lastType = arguments[varArgIndex].resolvedType; - if (lastType == TypeBinding.NULL - || (varArgsType.dimensions() == lastType.dimensions() - && lastType.isCompatibleWith(varArgsType))) { - // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is - arguments[varArgIndex].generateCode(currentScope, codeStream, true); - } else { - // right number but not directly compatible or too many arguments - wrap extra into array - // need to gen elements into an array, then gen each remaining element into created array - codeStream.generateInlinedValue(1); - codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array - codeStream.dup(); - codeStream.generateInlinedValue(0); - arguments[varArgIndex].generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - } else { // not enough arguments - pass extra empty array - // scenario: foo(1) --> foo(1, new int[0]) - // generate code for an empty array of parameterType + codeStream.dup(); codeStream.generateInlinedValue(0); - codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array + arguments[varArgIndex].generateCode(currentScope, codeStream, true); + codeStream.arrayAtPut(elementsTypeID, false); } - } else if (arguments != null) { // standard generation for method arguments - for (int i = 0, max = arguments.length; i < max; i++) - arguments[i].generateCode(currentScope, codeStream, true); + } else { // not enough arguments - pass extra empty array + // scenario: foo(1) --> foo(1, new int[0]) + // generate code for an empty array of parameterType + codeStream.generateInlinedValue(0); + codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array } + } else if (arguments != null) { // standard generation for method arguments + for (int i = 0, max = arguments.length; i < max; i++) + arguments[i].generateCode(currentScope, codeStream, true); } +} - public abstract void generateCode(BlockScope currentScope, CodeStream codeStream); - - public boolean isEmptyBlock() { - return false; - } +public abstract void generateCode(BlockScope currentScope, CodeStream codeStream); - public boolean isValidJavaStatement() { - //the use of this method should be avoid in most cases - //and is here mostly for documentation purpose..... - //while the parser is responsable for creating - //welled formed expression statement, which results - //in the fact that java-non-semantic-expression-used-as-statement - //should not be parsable...thus not being built. - //It sounds like the java grammar as help the compiler job in removing - //-by construction- some statement that would have no effect.... - //(for example all expression that may do side-effects are valid statement - // -this is an appromative idea.....-) +public boolean isEmptyBlock() { + return false; +} - return true; - } +public boolean isValidJavaStatement() { + //the use of this method should be avoid in most cases + //and is here mostly for documentation purpose..... + //while the parser is responsable for creating + //welled formed expression statement, which results + //in the fact that java-non-semantic-expression-used-as-statement + //should not be parsable...thus not being built. + //It sounds like the java grammar as help the compiler job in removing + //-by construction- some statement that would have no effect.... + //(for example all expression that may do side-effects are valid statement + // -this is an appromative idea.....-) - public StringBuffer print(int indent, StringBuffer output) { - return printStatement(indent, output); - } - public abstract StringBuffer printStatement(int indent, StringBuffer output); + return true; +} - public abstract void resolve(BlockScope scope); +public StringBuffer print(int indent, StringBuffer output) { + return printStatement(indent, output); +} - /** - * Returns case constant associated to this statement (NotAConstant if none) - */ - public Constant resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) { - // statement within a switch that are not case are treated as normal statement.... +public abstract StringBuffer printStatement(int indent, StringBuffer output); - resolve(scope); - return Constant.NotAConstant; - } +public abstract void resolve(BlockScope scope); +/** + * Returns case constant associated to this statement (NotAConstant if none) + */ +public Constant resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) { + // statement within a switch that are not case are treated as normal statement.... + resolve(scope); + return Constant.NotAConstant; +} } 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.53 diff -u -r1.53 ForeachStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java 19 Sep 2008 19:45:19 -0000 1.53 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java 21 Nov 2008 10:20:16 -0000 @@ -72,17 +72,15 @@ this.kind = -1; } - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // initialize break and continue labels this.breakLabel = new BranchLabel(); this.continueLabel = new BranchLabel(); + int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; // process the element variable and collection this.collection.checkNPE(currentScope, flowContext, flowInfo); - flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo); + flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo); FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy()); // element variable will be assigned when iterating @@ -101,10 +99,8 @@ if (!(this.action == null || (this.action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) { - if (!this.action.complainIfUnreachable(actionInfo, this.scope, false)) { - actionInfo = this.action. - analyseCode(this.scope, loopingContext, actionInfo). - unconditionalCopy(); + if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { + actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy(); } // code generation can be optimized when no need to continue in the loop 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.39 diff -u -r1.39 OR_OR_Expression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java 27 Jun 2008 16:03:55 -0000 1.39 +++ compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java 21 Nov 2008 10:20:16 -0000 @@ -56,7 +56,10 @@ int previousMode = rightInfo.reachMode(); if (isLeftOptimizedTrue){ - rightInfo.setReachMode(FlowInfo.UNREACHABLE); + if ((rightInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) { + currentScope.problemReporter().fakeReachable(this.right); + rightInfo.setReachMode(FlowInfo.UNREACHABLE); + } } rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo); FlowInfo mergedInfo = FlowInfo.conditional( Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v retrieving revision 1.381 diff -u -r1.381 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 18 Nov 2008 20:23:11 -0000 1.381 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 21 Nov 2008 10:20:18 -0000 @@ -42,10 +42,13 @@ CONSTRUCTOR_ACCESS = 0x8, METHOD_ACCESS = 0xC; +public ProblemReporter(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) { + super(policy, options, problemFactory); +} + private static int getElaborationId (int leadProblemId, byte elaborationVariant) { return leadProblemId << 8 | elaborationVariant; // leadProblemId comes into the higher order bytes } - public static int getIrritant(int problemID) { switch(problemID){ @@ -326,6 +329,9 @@ case IProblem.ShouldImplementHashcode: return CompilerOptions.ShouldImplementHashcode; + + case IProblem.DeadCode: + return CompilerOptions.DeadCode; } return 0; } @@ -375,6 +381,7 @@ case CompilerOptions.ComparingIdentical : case CompilerOptions.MissingSynchronizedModifierInInheritedMethod : case CompilerOptions.ShouldImplementHashcode : + case CompilerOptions.DeadCode : return CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM; case CompilerOptions.OverriddenPackageDefaultMethod : @@ -394,7 +401,7 @@ case CompilerOptions.UnhandledWarningToken : case CompilerOptions.UnusedWarningToken : case CompilerOptions.UnusedLabel : - case CompilerOptions.RedundantSuperinterface : + case CompilerOptions.RedundantSuperinterface : return CategorizedProblem.CAT_UNNECESSARY_CODE; case CompilerOptions.UsingDeprecatedAPI : @@ -442,9 +449,6 @@ } return CategorizedProblem.CAT_INTERNAL; } -public ProblemReporter(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) { - super(policy, options, problemFactory); -} public void abortDueToInternalError(String errorMessage) { this.abortDueToInternalError(errorMessage, null); } @@ -1248,6 +1252,7 @@ nodeSourceStart(field, location), nodeSourceEnd(field, location)); } + public void deprecatedMethod(MethodBinding method, ASTNode location) { boolean isConstructor = method.isConstructor(); int severity = computeSeverity(isConstructor ? IProblem.UsingDeprecatedConstructor : IProblem.UsingDeprecatedMethod); @@ -1332,7 +1337,6 @@ statement.sourceStart, statement.sourceEnd); } - public void duplicateEnumSpecialMethod(SourceTypeBinding type, AbstractMethodDeclaration methodDecl) { MethodBinding method = methodDecl.binding; this.handle( @@ -1348,6 +1352,7 @@ methodDecl.sourceStart, methodDecl.sourceEnd); } + public void duplicateFieldInType(SourceTypeBinding type, FieldDeclaration fieldDecl) { this.handle( IProblem.DuplicateField, @@ -1356,7 +1361,6 @@ fieldDecl.sourceStart, fieldDecl.sourceEnd); } - public void duplicateImport(ImportReference importRef) { String[] arguments = new String[] {CharOperation.toString(importRef.tokens)}; this.handle( @@ -1366,6 +1370,7 @@ importRef.sourceStart, importRef.sourceEnd); } + public void duplicateInheritedMethods(SourceTypeBinding type, MethodBinding inheritedMethod1, MethodBinding inheritedMethod2) { this.handle( IProblem.DuplicateParameterizedMethods, @@ -1400,7 +1405,6 @@ nodeSourceStart(local, location), nodeSourceEnd(local, location)); } - public void duplicateMethodInType(SourceTypeBinding type, AbstractMethodDeclaration methodDecl, boolean equalParameters) { MethodBinding method = methodDecl.binding; if (equalParameters) { @@ -1438,6 +1442,7 @@ methodDecl.sourceEnd); } } + public void duplicateModifierForField(ReferenceBinding type, FieldDeclaration fieldDecl) { /* to highlight modifiers use: this.handle( @@ -1638,6 +1643,21 @@ expression.sourceStart, expression.sourceEnd); } +public void fakeReachable(ASTNode location) { + int sourceStart = location.sourceStart; + int sourceEnd = location.sourceEnd; + if (location instanceof LocalDeclaration) { + LocalDeclaration declaration = (LocalDeclaration) location; + sourceStart = declaration.declarationSourceStart; + sourceEnd = declaration.declarationSourceEnd; + } + this.handle( + IProblem.DeadCode, + NoArgument, + NoArgument, + sourceStart, + sourceEnd); +} public void fieldHiding(FieldDeclaration fieldDecl, Binding hiddenVariable) { FieldBinding field = fieldDecl.binding; if (CharOperation.equals(TypeConstants.SERIALVERSIONUID, field.name) Index: compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties,v retrieving revision 1.242 diff -u -r1.242 messages.properties --- compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 10 Oct 2008 17:24:31 -0000 1.242 +++ compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 21 Nov 2008 10:20:18 -0000 @@ -122,6 +122,7 @@ 146 = Default constructor cannot handle exception type {0} thrown by implicit super constructor. Must define an explicit constructor 147 = Unhandled exception type {0} thrown by implicit super constructor +149 = Dead code 150 = The type of the expression must be an array type but it resolved to {0} 151 = Must explicitly convert the char[] to a String 152 = String constant is exceeding the limit of 65535 bytes of UTF8 encoding 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.335 diff -u -r1.335 Main.java --- batch/org/eclipse/jdt/internal/compiler/batch/Main.java 10 Oct 2008 17:24:31 -0000 1.335 +++ batch/org/eclipse/jdt/internal/compiler/batch/Main.java 21 Nov 2008 10:20:15 -0000 @@ -3141,6 +3141,11 @@ CompilerOptions.OPTION_ReportDiscouragedReference, isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE); return; + } else if (token.equals("deadCode")) { //$NON-NLS-1$ + this.options.put( + CompilerOptions.OPTION_ReportDeadCode, + isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE); + return; } break; case 'e' : 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.209 diff -u -r1.209 CompilerOptions.java --- compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 10 Oct 2008 17:24:31 -0000 1.209 +++ compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 21 Nov 2008 10:20:16 -0000 @@ -123,6 +123,7 @@ public static final String OPTION_ReportComparingIdentical = "org.eclipse.jdt.core.compiler.problem.comparingIdentical"; //$NON-NLS-1$ 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$ // Backward compatibility public static final String OPTION_ReportInvalidAnnotation = "org.eclipse.jdt.core.compiler.problem.invalidAnnotation"; //$NON-NLS-1$ @@ -225,7 +226,8 @@ public static final int MissingSynchronizedModifierInInheritedMethod= IrritantSet.GROUP1 | ASTNode.Bit29; // group 2 - public static final int ShouldImplementHashcode= IrritantSet.GROUP2 | ASTNode.Bit1; + public static final int ShouldImplementHashcode = IrritantSet.GROUP2 | ASTNode.Bit1; + public static final int DeadCode = IrritantSet.GROUP2 | ASTNode.Bit2; // Map: String optionKey --> Long irritant> private static Map OptionToIrritants; @@ -478,6 +480,8 @@ return OPTION_ReportMissingSynchronizedOnInheritedMethod; case ShouldImplementHashcode : return OPTION_ReportMissingHashCodeMethod; + case DeadCode : + return OPTION_ReportDeadCode; } return null; } @@ -580,6 +584,7 @@ OPTION_ReportAnnotationSuperInterface, OPTION_ReportAssertIdentifier, OPTION_ReportAutoboxing, + OPTION_ReportDeadCode, OPTION_ReportDeprecation, OPTION_ReportDiscouragedReference, OPTION_ReportEmptyStatement, @@ -893,6 +898,7 @@ optionsMap.put(OPTION_ReportComparingIdentical, getSeverityString(ComparingIdentical)); optionsMap.put(OPTION_ReportMissingSynchronizedOnInheritedMethod, getSeverityString(MissingSynchronizedModifierInInheritedMethod)); optionsMap.put(OPTION_ReportMissingHashCodeMethod, getSeverityString(ShouldImplementHashcode)); + optionsMap.put(OPTION_ReportDeadCode, getSeverityString(DeadCode)); return optionsMap; } @@ -1264,6 +1270,7 @@ if ((optionValue = optionsMap.get(OPTION_ReportComparingIdentical)) != null) updateSeverity(ComparingIdentical, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportMissingSynchronizedOnInheritedMethod)) != null) updateSeverity(MissingSynchronizedModifierInInheritedMethod, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportMissingHashCodeMethod)) != null) updateSeverity(ShouldImplementHashcode, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportDeadCode)) != null) updateSeverity(DeadCode, optionValue); // Javadoc options if ((optionValue = optionsMap.get(OPTION_DocCommentSupport)) != null) { @@ -1461,6 +1468,7 @@ buf.append("\n\t- comparing identical expr: ").append(getSeverityString(ComparingIdentical)); //$NON-NLS-1$ 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$ return buf.toString(); } Index: compiler/org/eclipse/jdt/core/compiler/IProblem.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java,v retrieving revision 1.206 diff -u -r1.206 IProblem.java --- compiler/org/eclipse/jdt/core/compiler/IProblem.java 10 Oct 2008 17:24:31 -0000 1.206 +++ compiler/org/eclipse/jdt/core/compiler/IProblem.java 21 Nov 2008 10:20:15 -0000 @@ -425,6 +425,7 @@ int UnhandledExceptionInImplicitConstructorCall = TypeRelated + 147; // expressions + int DeadCode = Internal + 149; int ArrayReferenceRequired = Internal + 150; int NoImplicitStringConversionForCharArrayExpression = Internal + 151; // constant expressions