Return in finally
Summary
- Rule ID:
return_in_finally - Name: Return in finally
- Description: Reports
returnstatements insidefinallyblocks because they can override exceptions or earlier returns and hide failures. - Annotation policy:
@Suppress/@SuppressWarningsare not supported; only JSpecify annotations are recognized for any annotation-driven semantics, and non-JSpecify annotations do not change behavior.
Motivation
Returning from a finally block changes control flow in a way that can discard an exception or prior return value. This makes failures disappear and results unpredictable, especially in large try/catch/finally blocks. The rule aims to prevent hidden failures and make cleanup code safer.
What it detects
- Any explicit
returnstatement located inside afinallyblock. returninfinallythat would override:- An exception thrown in the
tryorcatchblock. - A prior return value from the
tryorcatchblock. - Both value returns (e.g.,
return 1;) andreturn;invoidmethods.
What it does NOT detect
finallyblocks that do not contain areturn.- Returns that occur after the
try/finallyhas completed (for example, returning a local assigned infinally). - Suppression via annotations (
@Suppress,@SuppressWarnings) is not supported. - Non-JSpecify annotations do not affect rule behavior.
Examples (TP/TN/Edge)
True Positive
class ClassA {
int MethodX() {
try {
throw new RuntimeException("fail");
} finally {
return 1;
}
}
}
True Negative
class ClassB {
int MethodY() {
int varOne;
try {
varOne = 1;
} finally {
varOne = 2;
}
return varOne;
}
}
Edge Case
class ClassC {
int MethodZ() {
try {
return 1;
} finally {
return 2;
}
}
}
Output
- Message: "Return in finally overrides exceptions or prior returns. Move the return outside the finally block or return after the try/finally."
- Location: the
returnstatement within thefinallyblock.
Performance considerations
- Expected to be linear in method size.
- Should reuse existing control-flow and exception-table analysis where available.
Acceptance criteria
- Reports a finding for any
returninside afinallyblock that would override a thrown exception or earlier return. - Does not report when
finallyhas noreturnand the method returns after thetry/finallycompletes. - Produces actionable, user-facing messages as defined in Output.
- Applies the annotation policy exactly as stated in Summary.
- Examples above correspond to TP, TN, and Edge behavior.