-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathShouldUseWithStatement.ql
More file actions
46 lines (40 loc) · 1.77 KB
/
Copy pathShouldUseWithStatement.ql
File metadata and controls
46 lines (40 loc) · 1.77 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
/**
* @name Should use a 'with' statement
* @description Using a 'try-finally' block to ensure only that a resource is closed makes code more
* difficult to read.
* @kind problem
* @tags quality
* maintainability
* readability
* @problem.severity recommendation
* @sub-severity high
* @precision very-high
* @id py/should-use-with
*/
import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.DataFlowDispatch
private import semmle.python.dataflow.new.internal.ReExposedInstance
predicate calls_close(Call c) { exists(Attribute a | c.getFunc() = a and a.getName() = "close") }
predicate only_stmt_in_finally(Try t, Call c) {
exists(ExprStmt s |
t.getAFinalstmt() = s and s.getValue() = c and strictcount(t.getAFinalstmt()) = 1
)
}
/** Holds if `node` is tracked to be an instance of some class. */
private predicate classInstanceNode(DataFlow::Node node) { node = classInstanceTracker(_) }
private module ClassReExposed = ReExposedInstance<classInstanceNode/1>;
from Call close, Try t, Class cls, DataFlow::Node closeTarget
where
only_stmt_in_finally(t, close) and
calls_close(close) and
closeTarget.asExpr() = close.getFunc().(Attribute).getObject() and
closeTarget = classInstanceTracker(cls) and
// Don't report closing a resource that is held in an instance attribute (e.g. `self.reader`).
// Such flow is introduced by instance-attribute type tracking; the object's lifetime is tied
// to the enclosing instance and cannot be expressed with a `with` statement.
not ClassReExposed::isReExposed(closeTarget) and
DuckTyping::isContextManager(cls)
select close,
"Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement.",
cls, cls.getName()