diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java
index be3fcc3..542911f 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java
@@ -10,6 +10,7 @@
* Stephan Herrmann - Contributions for
* bug 358827 - [1.7] exception analysis for t-w-r spoils null analysis
* bug 349326 - [1.7] new warning for missing try-with-resources
+ * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -4942,6 +4943,45 @@
true,
options);
}
+// Bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points
+public void test056throw1() {
+ Map options = getCompilerOptions();
+ options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR);
+ options.put(JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR);
+ options.put(JavaCore.COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE, CompilerOptions.ERROR);
+ options.put(JavaCore.COMPILER_PB_DEAD_CODE, CompilerOptions.ERROR);
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.io.FileReader;\n" +
+ "public class X {\n" +
+ " void foo2(boolean a, boolean b, boolean c) throws Exception {\n" +
+ " FileReader reader = new FileReader(\"file\");\n" +
+ " if(a)\n" +
+ " throw new Exception(); //warning 1\n" +
+ " else if (b)\n" +
+ " reader.close();\n" +
+ " else if(c)\n" +
+ " throw new Exception(); //warning 2\n" +
+ " reader.close();\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 6)\n" +
+ " throw new Exception(); //warning 1\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Resource leak: \'reader\' is not closed at this location\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 10)\n" +
+ " throw new Exception(); //warning 2\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Resource leak: \'reader\' is not closed at this location\n" +
+ "----------\n",
+ null,
+ true,
+ options);
+}
public static Class testClass() {
return TryWithResourcesStatementTest.class;
}
diff --git a/org.eclipse.jdt.core/buildnotes_jdt-core.html b/org.eclipse.jdt.core/buildnotes_jdt-core.html
index 2066a8c..26db9ea 100644
--- a/org.eclipse.jdt.core/buildnotes_jdt-core.html
+++ b/org.eclipse.jdt.core/buildnotes_jdt-core.html
@@ -52,7 +52,9 @@
What's new in this drop
Problem Reports Fixed
-359362
+359334
+Analysis for resource leak warnings does not consider exceptions as method exit points
+
359362
FUP of bug 349326: Resource leak on non-Closeable resource.
348186
[compiler] Improve wording for the warning for masked/hidden catch block
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
index f446ce9..6a80298 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
@@ -33,12 +33,12 @@
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, flowContext, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
+ if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo);
}
}
if (this.explicitDeclarations > 0) // if block has its own scope analyze tracking vars now:
- this.scope.checkUnclosedCloseables(flowInfo, flowContext, null);
+ this.scope.checkUnclosedCloseables(flowInfo, null);
return flowInfo;
}
/**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index 9ff71db..5907c61 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -66,7 +66,7 @@
trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
}
if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) {
- this.valueIfTrue.complainIfUnreachable(trueFlowInfo, flowContext, currentScope, initialComplaintLevel, false);
+ this.valueIfTrue.complainIfUnreachable(trueFlowInfo, currentScope, initialComplaintLevel, false);
}
}
this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo);
@@ -79,7 +79,7 @@
falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
}
if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) {
- this.valueIfFalse.complainIfUnreachable(falseFlowInfo, flowContext, currentScope, initialComplaintLevel, true);
+ this.valueIfFalse.complainIfUnreachable(falseFlowInfo, currentScope, initialComplaintLevel, true);
}
}
this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
index 99def1c..d8e3818 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
@@ -153,7 +153,7 @@
int complaintLevel = (nonStaticFieldInfoReachMode & FlowInfo.UNREACHABLE) == 0 ? Statement.NOT_COMPLAINED : Statement.COMPLAINED_FAKE_REACHABLE;
for (int i = 0, count = this.statements.length; i < count; i++) {
Statement stat = this.statements[i];
- if ((complaintLevel = stat.complainIfUnreachable(flowInfo, constructorContext, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
+ if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo);
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java
index b74fded..904e564 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java
@@ -30,12 +30,12 @@
}
// Report an error if necessary
- public int complainIfUnreachable(FlowInfo flowInfo, FlowContext flowContext, BlockScope scope, int complaintLevel, boolean endOfBlock) {
+ public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int complaintLevel, boolean endOfBlock) {
// before 1.4, empty statements are tolerated anywhere
if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_4) {
return complaintLevel;
}
- return super.complainIfUnreachable(flowInfo, flowContext, scope, complaintLevel, endOfBlock);
+ return super.complainIfUnreachable(flowInfo, scope, complaintLevel, endOfBlock);
}
public void generateCode(BlockScope currentScope, CodeStream codeStream){
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
index e816169..75ca5bf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
@@ -140,7 +140,7 @@
actionInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
}
}
- if (this.action.complainIfUnreachable(actionInfo, flowContext, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
+ if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits();
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
index 6d8e62d..44d3b61 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
@@ -100,7 +100,7 @@
if (!(this.action == null || (this.action.isEmptyBlock()
&& currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) {
- if (this.action.complainIfUnreachable(actionInfo, flowContext, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
+ if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy();
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
index 2b9c876..a70662c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
@@ -91,7 +91,7 @@
this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo);
if (isConditionOptimizedFalse || ((this.bits & ASTNode.IsThenStatementUnreachable) != 0)) {
if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) {
- this.thenStatement.complainIfUnreachable(thenFlowInfo, flowContext, currentScope, initialComplaintLevel, false);
+ this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, initialComplaintLevel, false);
} else {
// its a known coding pattern which should be tolerated by dead code analysis
// according to isKnowDeadCodePattern()
@@ -117,7 +117,7 @@
this.elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo);
if (isConditionOptimizedTrue || ((this.bits & ASTNode.IsElseStatementUnreachable) != 0)) {
if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) {
- this.elseStatement.complainIfUnreachable(elseFlowInfo, flowContext, currentScope, initialComplaintLevel, false);
+ this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, initialComplaintLevel, false);
} else {
// its a known coding pattern which should be tolerated by dead code analysis
// according to isKnowDeadCodePattern()
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
index ab7e7f6..5fa2895 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
@@ -101,7 +101,7 @@
int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) == 0 ? Statement.NOT_COMPLAINED : Statement.COMPLAINED_FAKE_REACHABLE;
for (int i = 0, count = this.statements.length; i < count; i++) {
Statement stat = this.statements[i];
- if ((complaintLevel = stat.complainIfUnreachable(flowInfo, methodContext, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
+ if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo);
}
}
@@ -135,7 +135,7 @@
}
}
- this.scope.checkUnclosedCloseables(flowInfo, methodContext, null/*don't report against a specific location*/);
+ this.scope.checkUnclosedCloseables(flowInfo, null/*don't report against a specific location*/);
} catch (AbortMethod e) {
this.ignoreFurtherInvestigation = true;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
index 1be2ead..c1f3c4d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
@@ -114,7 +114,7 @@
this.expression.bits |= ASTNode.IsReturnedValue;
}
}
- currentScope.checkUnclosedCloseables(flowInfo, null/*ignore exception exits from flowContext*/, this);
+ currentScope.checkUnclosedCloseables(flowInfo, this);
return FlowInfo.DEAD_END;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index fb056b6..a6c1b75 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -72,7 +72,7 @@
// 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, FlowContext flowContext, BlockScope scope, int previousComplaintLevel, boolean endOfBlock) {
+public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previousComplaintLevel, boolean endOfBlock) {
if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) {
if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
this.bits &= ~ASTNode.IsReachable;
@@ -80,14 +80,14 @@
if (previousComplaintLevel < COMPLAINED_UNREACHABLE) {
scope.problemReporter().unreachableCode(this);
if (endOfBlock)
- scope.checkUnclosedCloseables(flowInfo, flowContext, null);
+ scope.checkUnclosedCloseables(flowInfo, null);
}
return COMPLAINED_UNREACHABLE;
} else {
if (previousComplaintLevel < COMPLAINED_FAKE_REACHABLE) {
scope.problemReporter().fakeReachable(this);
if (endOfBlock)
- scope.checkUnclosedCloseables(flowInfo, flowContext, null);
+ scope.checkUnclosedCloseables(flowInfo, null);
}
return COMPLAINED_FAKE_REACHABLE;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index 21c1ca0..609a8a5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -101,7 +101,7 @@
} else {
fallThroughState = FALLTHROUGH; // reset below if needed
}
- if ((complaintLevel = statement.complainIfUnreachable(caseInits, flowContext, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
+ if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
caseInits = statement.analyseCode(this.scope, switchContext, caseInits);
if (caseInits == FlowInfo.DEAD_END) {
fallThroughState = ESCAPING;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
index 7e3d4c2..1d83852 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -35,6 +36,7 @@
this.exception.checkNPE(currentScope, flowContext, flowInfo);
// need to check that exception thrown is actually caught somewhere
flowContext.checkExceptionHandlers(this.exceptionType, this, flowInfo, currentScope);
+ currentScope.checkUnclosedCloseables(flowInfo, this);
return FlowInfo.DEAD_END;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
index 8ead6d4..e35ea9c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
@@ -115,7 +115,7 @@
currentScope.methodScope().recordInitializationStates(
condInfo.initsWhenTrue());
- if (this.action.complainIfUnreachable(actionInfo, flowContext, currentScope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
+ if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
index 0ca801d..f4e2ae3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
@@ -18,7 +18,6 @@
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
-import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
@@ -988,11 +987,11 @@
* At the end of a block check the closing-status of all tracked closeables that are declared in this block.
* Also invoked when entering unreachable code.
*/
-public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext, ASTNode location) {
+public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location) {
if (this.trackingVariables == null) {
// at a method return we also consider enclosing scopes
if (location != null && this.parent instanceof BlockScope)
- ((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, flowContext, location);
+ ((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, location);
return;
}
if (location != null && flowInfo.reachMode() != 0) return;