-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathStmts.qll
More file actions
516 lines (416 loc) · 14.7 KB
/
Stmts.qll
File metadata and controls
516 lines (416 loc) · 14.7 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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
overlay[local]
module;
import python
/** A statement */
class Stmt extends Stmt_, AstNode {
/** Gets the scope immediately enclosing this statement */
override Scope getScope() { py_scopes(this, result) }
override string toString() { result = "Stmt" }
/** Gets the module enclosing this statement */
Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
override Location getLocation() { result = Stmt_.super.getLocation() }
/** Gets an immediate (non-nested) sub-expression of this statement */
Expr getASubExpression() { none() }
/** Gets an immediate (non-nested) sub-statement of this statement */
Stmt getASubStatement() { none() }
/** Gets an immediate (non-nested) sub-pattern of this statement */
Pattern getASubPattern() { none() }
override AstNode getAChildNode() {
result = this.getASubExpression()
or
result = this.getASubStatement()
or
result = this.getASubPattern()
}
private ControlFlowNode possibleEntryNode() {
result.getNode() = this or
this.containsInScope(result.getNode())
}
/**
* Gets a control flow node for an entry into this statement.
*/
ControlFlowNode getAnEntryNode() {
result = this.possibleEntryNode() and
exists(ControlFlowNode pred |
pred.getASuccessor() = result and
not pred = this.possibleEntryNode()
)
}
/** Holds if this statement cannot be reached */
predicate isUnreachable() {
not exists(this.getAnEntryNode())
or
exists(If ifstmt |
ifstmt.getTest().(ImmutableLiteral).booleanValue() = false and ifstmt.getBody().contains(this)
or
ifstmt.getTest().(ImmutableLiteral).booleanValue() = true and
ifstmt.getOrelse().contains(this)
)
or
exists(While whilestmt |
whilestmt.getTest().(ImmutableLiteral).booleanValue() = false and
whilestmt.getBody().contains(this)
)
}
/**
* Gets the final statement in this statement, ordered by location.
* Will be this statement if not a compound statement.
*/
Stmt getLastStatement() { result = this }
}
/** A statement that includes a binding (except imports) */
class Assign extends Assign_ {
/** Use ControlFlowNodes and SsaVariables for data-flow analysis. */
predicate defines(Variable v) { this.getATarget().defines(v) }
override Expr getASubExpression() {
result = this.getATarget() or
result = this.getValue()
}
override Stmt getASubStatement() { none() }
}
/** An assignment statement */
class AssignStmt extends Assign {
/* syntax: Expr, ... = Expr */
AssignStmt() { not this instanceof FunctionDef and not this instanceof ClassDef }
override string toString() { result = "AssignStmt" }
}
/** An augmented assignment statement, such as `x += y` */
class AugAssign extends AugAssign_ {
/* syntax: Expr += Expr */
override Expr getASubExpression() { result = this.getOperation() }
/**
* Gets the target of this augmented assignment statement.
* That is, the `a` in `a += b`.
*/
Expr getTarget() { result = this.getOperation().getLeft() }
/**
* Gets the value of this augmented assignment statement.
* That is, the `b` in `a += b`.
*/
Expr getValue() { result = this.getOperation().getRight() }
override Stmt getASubStatement() { none() }
}
/** An annotated assignment statement, such as `x: int = 0` */
class AnnAssign extends AnnAssign_ {
/* syntax: Expr: Expr = Expr */
override Expr getASubExpression() {
result = this.getAnnotation() or
result = this.getTarget() or
result = this.getValue()
}
override Stmt getASubStatement() { none() }
/** Holds if the value of the annotation of this assignment is stored at runtime. */
predicate isStored() {
not this.getScope() instanceof Function and
exists(Name n |
n = this.getTarget() and
not n.isParenthesized()
)
}
}
/** An exec statement */
class Exec extends Exec_ {
/* syntax: exec Expr */
override Expr getASubExpression() {
result = this.getBody() or
result = this.getGlobals() or
result = this.getLocals()
}
override Stmt getASubStatement() { none() }
}
/**
* An exception handler such as an `except` or an `except*` statement
* in a `try` statement.
*/
class ExceptionHandler extends Stmt {
ExceptionHandler() {
this instanceof ExceptStmt_
or
this instanceof ExceptGroupStmt_
}
/** Gets the immediately enclosing try statement */
Try getTry() { result.getAHandler() = this }
/** Gets the name of this except group block. */
abstract Expr getName();
/** Gets the type of this except group block. */
abstract Expr getType();
}
/** An except group statement (part of a `try` statement), such as `except* IOError as err:` */
class ExceptGroupStmt extends ExceptGroupStmt_, ExceptionHandler {
/* syntax: except Expr [ as Expr ]: */
override Expr getASubExpression() {
result = this.getName()
or
result = this.getType()
}
override Stmt getASubStatement() { result = this.getAStmt() }
override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() }
override Expr getName() { result = ExceptGroupStmt_.super.getName() }
override Expr getType() {
result = ExceptGroupStmt_.super.getType() and not result instanceof Tuple
or
result = ExceptGroupStmt_.super.getType().(Tuple).getAnElt()
}
}
/** An except statement (part of a `try` statement), such as `except IOError as err:` */
class ExceptStmt extends ExceptStmt_, ExceptionHandler {
/* syntax: except Expr [ as Expr ]: */
override Expr getASubExpression() {
result = this.getName()
or
result = this.getType()
}
override Stmt getASubStatement() { result = this.getAStmt() }
override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() }
override Expr getName() { result = ExceptStmt_.super.getName() }
override Expr getType() {
result = ExceptStmt_.super.getType() and not result instanceof Tuple
or
result = ExceptStmt_.super.getType().(Tuple).getAnElt()
}
}
/** An assert statement, such as `assert a == b, "A is not equal to b"` */
class Assert extends Assert_ {
/* syntax: assert Expr [, Expr] */
override Expr getASubExpression() { result = this.getMsg() or result = this.getTest() }
override Stmt getASubStatement() { none() }
}
/** A break statement */
class Break extends Break_ {
/* syntax: assert Expr [, Expr] */
override Expr getASubExpression() { none() }
override Stmt getASubStatement() { none() }
}
/** A continue statement */
class Continue extends Continue_ {
/* syntax: continue */
override Expr getASubExpression() { none() }
override Stmt getASubStatement() { none() }
}
/** A delete statement, such as `del x[-1]` */
class Delete extends Delete_ {
/* syntax: del Expr, ... */
override Expr getASubExpression() { result = this.getATarget() }
override Stmt getASubStatement() { none() }
}
/** An expression statement, such as `len(x)` or `yield y` */
class ExprStmt extends ExprStmt_ {
/* syntax: Expr */
override Expr getASubExpression() { result = this.getValue() }
override Stmt getASubStatement() { none() }
}
/** A for statement, such as `for x in y: print(x)` */
class For extends For_ {
/* syntax: for varname in Expr: ... */
override Stmt getASubStatement() {
result = this.getAStmt() or
result = this.getAnOrelse()
}
override Expr getASubExpression() {
result = this.getTarget() or
result = this.getIter()
}
override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() }
}
/** A global statement, such as `global var` */
class Global extends Global_ {
/* syntax: global varname */
override Expr getASubExpression() { none() }
override Stmt getASubStatement() { none() }
}
/** An if statement, such as `if eggs: print("spam")` */
class If extends If_ {
/* syntax: if Expr: ... */
override Stmt getASubStatement() {
result = this.getAStmt() or
result = this.getAnOrelse()
}
override Expr getASubExpression() { result = this.getTest() }
/** Whether this if statement takes the form `if __name__ == "__main__":` */
predicate isNameEqMain() {
exists(StringLiteral m, Name n, Compare c |
this.getTest() = c and
c.getOp(0) instanceof Eq and
(
c.getLeft() = n and c.getComparator(0) = m
or
c.getLeft() = m and c.getComparator(0) = n
) and
n.getId() = "__name__" and
m.getText() = "__main__"
)
}
/** Whether this if statement starts with the keyword `elif` */
predicate isElif() {
/*
* The Python parser turns all elif chains into nested if-else statements.
* An `elif` can be identified as it is the first statement in an `else` block
* and it is not indented relative to its parent `if`.
*/
exists(If i |
i.getOrelse(0) = this and
this.getLocation().getStartColumn() = i.getLocation().getStartColumn()
)
}
/** Gets the `elif` branch of this `if`-statement, if present */
If getElif() {
result = this.getOrelse(0) and
result.isElif()
}
override Stmt getLastStatement() {
result = this.getOrelse().getLastItem().getLastStatement()
or
not exists(this.getOrelse()) and
result = this.getBody().getLastItem().getLastStatement()
}
}
/** A nonlocal statement, such as `nonlocal var` */
class Nonlocal extends Nonlocal_ {
/* syntax: nonlocal varname */
override Stmt getASubStatement() { none() }
override Expr getASubExpression() { none() }
Variable getAVariable() {
result.getScope() = this.getScope() and
result.getId() = this.getAName()
}
}
/** A pass statement */
class Pass extends Pass_ {
/* syntax: pass */
override Stmt getASubStatement() { none() }
override Expr getASubExpression() { none() }
}
/** A print statement (Python 2 only), such as `print 0` */
class Print extends Print_ {
/* syntax: print Expr, ... */
override Stmt getASubStatement() { none() }
override Expr getASubExpression() {
result = this.getAValue() or
result = this.getDest()
}
}
/** A raise statement, such as `raise CompletelyDifferentException()` */
class Raise extends Raise_ {
/* syntax: raise Expr */
override Stmt getASubStatement() { none() }
override Expr getASubExpression() { py_exprs(result, _, this, _) }
/**
* Gets the expression immediately following the `raise`. This is the
* exception raised, but not accounting for tuples in Python 2.
*/
Expr getException() {
result = this.getType()
or
result = this.getExc()
}
/** Gets the exception raised, accounting for tuples in Python 2. */
Expr getRaised() {
exists(Expr raw | raw = this.getException() |
if not major_version() = 2 or not exists(raw.(Tuple).getAnElt())
then result = raw
else
/* In Python 2 raising a tuple will result in the first element of the tuple being raised. */
result = raw.(Tuple).getElt(0)
)
}
}
/** A return statement, such as return None */
class Return extends Return_ {
/* syntax: return Expr */
override Stmt getASubStatement() { none() }
override Expr getASubExpression() { result = this.getValue() }
}
/** A try statement */
class Try extends Try_ {
/* syntax: try: ... */
override Expr getASubExpression() { none() }
override Stmt getASubStatement() {
result = this.getAHandler() or
result = this.getAStmt() or
result = this.getAFinalstmt() or
result = this.getAnOrelse()
}
override ExceptionHandler getHandler(int i) { result = Try_.super.getHandler(i) }
override ExceptionHandler getAHandler() { result = Try_.super.getAHandler() }
/** Gets a normal exception handler, `except`, of this try statement. */
ExceptStmt getANormalHandler() { result = this.getAHandler() }
/** Gets a group exception handler, `except*`, of this try statement. */
ExceptGroupStmt getAGroupHandler() { result = this.getAHandler() }
override Stmt getLastStatement() {
result = this.getFinalbody().getLastItem().getLastStatement()
or
not exists(this.getFinalbody()) and
result = this.getOrelse().getLastItem().getLastStatement()
or
not exists(this.getFinalbody()) and
not exists(this.getOrelse()) and
result = this.getHandlers().getLastItem().getLastStatement()
or
not exists(this.getFinalbody()) and
not exists(this.getOrelse()) and
not exists(this.getHandlers()) and
result = this.getBody().getLastItem().getLastStatement()
}
}
/** A while statement, such as `while parrot_resting():` */
class While extends While_ {
/* syntax: while Expr: ... */
override Expr getASubExpression() { result = this.getTest() }
override Stmt getASubStatement() {
result = this.getAStmt() or
result = this.getAnOrelse()
}
override Stmt getLastStatement() {
result = this.getOrelse().getLastItem().getLastStatement()
or
not exists(this.getOrelse()) and
result = this.getBody().getLastItem().getLastStatement()
}
}
/** A with statement such as `with f as open("file"): text = f.read()` */
class With extends With_ {
/* syntax: with Expr as varname: ... */
override Expr getASubExpression() {
result = this.getContextExpr() or
result = this.getOptionalVars()
}
override Stmt getASubStatement() { result = this.getAStmt() }
override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() }
}
/** A match statement */
class MatchStmt extends MatchStmt_ {
/* syntax: match subject: */
override Expr getASubExpression() { result = this.getSubject() }
override Stmt getASubStatement() { result = this.getCase(_) }
}
/** A case statement */
class Case extends Case_ {
/* syntax: case pattern if guard: */
override Expr getASubExpression() { result = this.getGuard() }
override Stmt getASubStatement() { result = this.getStmt(_) }
override Pattern getASubPattern() { result = this.getPattern() }
}
/** A plain text used in a template is wrapped in a TemplateWrite statement */
class TemplateWrite extends TemplateWrite_ {
override Expr getASubExpression() { result = this.getValue() }
override Stmt getASubStatement() { none() }
}
/** An asynchronous `for` statement, such as `async for varname in Expr: ...` */
class AsyncFor extends For {
/* syntax: async for varname in Expr: ... */
AsyncFor() { this.isAsync() }
}
/** An asynchronous `with` statement, such as `async with varname as Expr: ...` */
class AsyncWith extends With {
/* syntax: async with Expr as varname: ... */
AsyncWith() { this.isAsync() }
}
/** A list of statements */
class StmtList extends StmtList_ {
/** Holds if this list of statements contains the AST node `a` */
predicate contains(AstNode a) {
exists(Stmt item | item = this.getAnItem() | item = a or item.contains(a))
}
/** Gets the last item in this list of statements, if any. */
Stmt getLastItem() { result = this.getItem(max(int i | exists(this.getItem(i)))) }
}