mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
514 lines
15 KiB
Plaintext
514 lines
15 KiB
Plaintext
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)))) }
|
|
}
|