-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathUnusedExceptionObject.ql
More file actions
60 lines (55 loc) · 1.67 KB
/
UnusedExceptionObject.ql
File metadata and controls
60 lines (55 loc) · 1.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* @name Unused exception object
* @description An exception object is created, but is not used.
* @kind problem
* @tags quality
* reliability
* error-handling
* @problem.severity error
* @sub-severity low
* @precision very-high
* @id py/unused-exception-object
*/
import python
private import semmle.python.dataflow.new.internal.DataFlowDispatch
private import semmle.python.dataflow.new.internal.Builtins
private import semmle.python.ApiGraphs
/**
* Holds if `cls` is a user-defined exception class, i.e. it transitively
* extends one of the builtin exception base classes.
*/
predicate isUserDefinedExceptionClass(Class cls) {
cls.getABase() =
API::builtin(["BaseException", "Exception"]).getAValueReachableFromSource().asExpr()
or
isUserDefinedExceptionClass(getADirectSuperclass(cls))
}
/**
* Gets the name of a builtin exception class.
*/
string getBuiltinExceptionName() {
result = Builtins::getBuiltinName() and
(
result.matches("%Error") or
result.matches("%Exception") or
result.matches("%Warning") or
result =
["GeneratorExit", "KeyboardInterrupt", "StopIteration", "StopAsyncIteration", "SystemExit"]
)
}
/**
* Holds if `call` is an instantiation of an exception class.
*/
predicate isExceptionInstantiation(Call call) {
exists(Class cls |
classTracker(cls).asExpr() = call.getFunc() and
isUserDefinedExceptionClass(cls)
)
or
call.getFunc() = API::builtin(getBuiltinExceptionName()).getAValueReachableFromSource().asExpr()
}
from Call call
where
isExceptionInstantiation(call) and
exists(ExprStmt s | s.getValue() = call)
select call, "Instantiating an exception, but not raising it, has no effect."