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:
Clément Fournier committed 2021-05-11 15:14:29 +02:00
1 parent 8bba9b070b
commit 7b693aae1a
2 files changed
+53 -9

No files matched your search

@@ -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;
}
}
@@ -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>