Skip to content

Commit 6bd84af

Browse files
committed
Java: Handle missing throws clauses.
1 parent ad7e913 commit 6bd84af

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

java/ql/lib/semmle/code/java/ControlFlowGraph.qll

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,50 @@ private module Exceptions {
285285
)
286286
}
287287

288+
/**
289+
* Holds if a catch clause of `try` catches checked exceptions of type
290+
* `caught`, and that `call` is contained within the try block.
291+
*/
292+
private predicate checkedExceptionFromCatchCandidate(TryStmt try, RefType caught, Call call) {
293+
(
294+
call.getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or
295+
call.(Expr).getParent*() = try.getAResource()
296+
) and
297+
try.getACatchClause().getACaughtType() = caught and
298+
not caught instanceof UncheckedThrowableSuperType
299+
}
300+
301+
/**
302+
* Holds if a catch clause of `try` catches checked exceptions of type
303+
* `caught`, and that there is a call within the try block that declares that
304+
* it may throw `caught` or a subtype thereof.
305+
*/
306+
private predicate declaredCheckedExceptionFromCatchCandidate(TryStmt try, RefType caught) {
307+
exists(Call call |
308+
checkedExceptionFromCatchCandidate(try, caught, call) and
309+
call.getCallee().getAThrownExceptionType().getASourceSupertype*() = caught
310+
)
311+
}
312+
313+
/**
314+
* Holds if `call` is contained within a try block that has a catch clause
315+
* that catches a checked exception, but there is no call within the try
316+
* block that declares that it may throw that exception, and no throw
317+
* statement either. In this case, it is likely that the throws declaration
318+
* for some reason was not extracted, so we conseratively assume that `call`
319+
* may throw such an exception.
320+
*/
321+
private predicate checkedExceptionFromCatchCandidate(Call call) {
322+
exists(TryStmt try, RefType caught |
323+
checkedExceptionFromCatchCandidate(try, caught, call) and
324+
not declaredCheckedExceptionFromCatchCandidate(try, caught) and
325+
not exists(ThrowStmt throwstmt |
326+
throwstmt.getEnclosingStmt+() = try.getBlock() and
327+
throwstmt.getThrownExceptionType().getASourceSupertype*() = caught
328+
)
329+
)
330+
}
331+
288332
/**
289333
* Holds if `n` is expected to possibly throw an exception. This can either
290334
* be due to a declared (likely checked) exception on a call target
@@ -293,6 +337,8 @@ private module Exceptions {
293337
predicate mayThrow(Ast::AstNode n) {
294338
exists(n.(Call).getCallee().getAThrownExceptionType())
295339
or
340+
checkedExceptionFromCatchCandidate(n)
341+
or
296342
uncheckedExceptionFromMethod(n)
297343
or
298344
uncheckedExceptionFromFinally(n)

0 commit comments

Comments
 (0)