Ignore new Exception(new Problem(originalException))
These are cases where the exception is consumed by the constructor transitively. Since we're processing everything recursively now we're effectively exploring the dataflow graph... only in an indirect way, without respect for ordering of statements... This can be improved later, and ideally generalized to help other rules.
This commit is contained in:
2 files changed
+53
-9
No files matched your search
+8
-8
@@ -93,25 +93,25 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// we don't know
|
||||
return true;
|
||||
// assume it doesn't
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean ctorConsumesException(ASTVariableDeclaratorId exceptionParam, ASTConstructorCall ctorCall) {
|
||||
return ctorCall.isAnonymousClass() && callsInitCauseInAnonInitializer(exceptionParam, ctorCall)
|
||||
|| hasReferenceAsArgument(ctorCall, exceptionParam);
|
||||
|| anArgumentConsumesException(exceptionParam, ctorCall);
|
||||
}
|
||||
|
||||
private static boolean consumesExceptionNonRecursive(ASTVariableDeclaratorId exceptionParam, ASTExpression expr) {
|
||||
if (expr instanceof ASTConstructorCall) {
|
||||
return ctorConsumesException(exceptionParam, (ASTConstructorCall) expr);
|
||||
}
|
||||
return expr instanceof InvocationNode && hasReferenceAsArgument((InvocationNode) expr, exceptionParam);
|
||||
return expr instanceof InvocationNode && anArgumentConsumesException(exceptionParam, (InvocationNode) expr);
|
||||
}
|
||||
|
||||
private static boolean methodConsumesException(ASTVariableDeclaratorId exceptionParam, ASTMethodCall call) {
|
||||
if (hasReferenceAsArgument(call, exceptionParam)) {
|
||||
if (anArgumentConsumesException(exceptionParam, call)) {
|
||||
return true;
|
||||
}
|
||||
ASTExpression qualifier = call.getQualifier();
|
||||
@@ -130,14 +130,14 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
|
||||
|
||||
private static boolean isInitCauseWithTargetInArg(ASTVariableDeclaratorId exceptionSym, JavaNode expr) {
|
||||
if (INIT_CAUSE.matchesCall(expr)) {
|
||||
return hasReferenceAsArgument((ASTMethodCall) expr, exceptionSym);
|
||||
return anArgumentConsumesException(exceptionSym, (ASTMethodCall) expr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasReferenceAsArgument(InvocationNode thrownExpr, @NonNull ASTVariableDeclaratorId toFind) {
|
||||
private static boolean anArgumentConsumesException(@NonNull ASTVariableDeclaratorId exceptionParam, InvocationNode thrownExpr) {
|
||||
for (ASTExpression arg : ASTList.orEmptyStream(thrownExpr.getArguments())) {
|
||||
if (JavaRuleUtil.isReferenceToVar(arg, toFind.getSymbol())) {
|
||||
if (exprConsumesException(exceptionParam, arg, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+45
-1
@@ -265,6 +265,7 @@ public class B {
|
||||
<test-code>
|
||||
<description>14, Nested with same name catch and throw, fail on inner</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>7</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
public class B {
|
||||
public void bla() {
|
||||
@@ -669,7 +670,7 @@ public class SomeOtherUserDefinedException extends Exception {
|
||||
|
||||
<test-code>
|
||||
<description>#2134 [java] PreserveStackTrace not handling Throwable.addSuppressed(...)</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import java.io.IOException;
|
||||
public class Foo {
|
||||
@@ -817,4 +818,47 @@ public class SomeOtherUserDefinedException extends Exception {
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Arguments may consume exception recursively</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
|
||||
public void foo(String a) {
|
||||
try {
|
||||
System.out.println(a);
|
||||
} catch (NumberFormatException ex) {
|
||||
// the exception is consumed by a constructor, which is
|
||||
// consumed by the thrown expression
|
||||
throw new InternalParseException(new SpelParseException(ex, "SpelMessage.NOT_A_LONG", "numberToken"));
|
||||
}
|
||||
}
|
||||
|
||||
static class InternalParseException {}
|
||||
static class SpelParseException {}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>Arguments may consume exception recursively, even across variables</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
|
||||
public void foo(String a) {
|
||||
try {
|
||||
System.out.println(a);
|
||||
} catch (NumberFormatException ex) {
|
||||
// same as above with intermediary variable
|
||||
SpelParseException other = new SpelParseException(ex, "SpelMessage.NOT_A_LONG", "numberToken");
|
||||
throw new InternalParseException(other);
|
||||
}
|
||||
}
|
||||
|
||||
static class InternalParseException { }
|
||||
static class SpelParseException { }
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
</test-data>
|
||||
Reference in new issue
Block a user