Skip to content

Commit de8ecb2

Browse files
committed
python: Wrappers for database classes
- new syntactic category `Pattern` (in `Patterns.qll`) - subpatterns available on statments - new statements `MatchStmt` and `Case` (`Match` would conflict with the shared ReDoS library) - new expression `Guard` - support for pattern lists
1 parent b17f844 commit de8ecb2

File tree

5 files changed

+162
-0
lines changed

5 files changed

+162
-0
lines changed

python/ql/lib/python.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import semmle.python.Class
1010
import semmle.python.Import
1111
import semmle.python.Stmts
1212
import semmle.python.Exprs
13+
import semmle.python.Patterns
1314
import semmle.python.Keywords
1415
import semmle.python.Comprehensions
1516
import semmle.python.Flow

python/ql/lib/semmle/python/AstExtended.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ library class StrListParent extends StrListParent_ { }
8282
/** Internal implementation class */
8383
library class ExprParent extends ExprParent_ { }
8484

85+
/** Internal implementation class */
86+
library class PatternListParent extends PatternListParent_ { }
87+
88+
/** Internal implementation class */
89+
library class PatternParent extends PatternParent_ { }
90+
8591
library class DictItem extends DictItem_, AstNode {
8692
override string toString() { result = DictItem_.super.toString() }
8793

@@ -162,6 +168,9 @@ class ExprList extends ExprList_ {
162168
/* syntax: Expr, ... */
163169
}
164170

171+
/** A list of patterns */
172+
class PatternList extends PatternList_ { }
173+
165174
library class DictItemList extends DictItemList_ { }
166175

167176
library class DictItemListParent extends DictItemListParent_ { }

python/ql/lib/semmle/python/Exprs.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,12 @@ class FormattedValue extends FormattedValue_ {
718718
}
719719
}
720720

721+
/** A guard in a case statement */
722+
class Guard extends Guard_ {
723+
/* syntax: if Expr */
724+
override Expr getASubExpression() { result = this.getTest() }
725+
}
726+
721727
/* Expression Contexts */
722728
/** A context in which an expression used */
723729
class ExprContext extends ExprContext_ { }
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* Wrapping generated AST classes: `Pattern_` and subclasses.
3+
*/
4+
5+
import python
6+
7+
/** A pattern in a match statement */
8+
class Pattern extends Pattern_, AstNode {
9+
/** Gets the scope of this pattern */
10+
override Scope getScope() {
11+
// TODO: Should it be defined as
12+
// py_scopes(this, result)
13+
// instead?
14+
result = this.getCase().getScope()
15+
}
16+
17+
/** Gets the case statement containing this pattern */
18+
Case getCase() { result.contains(this) }
19+
20+
override string toString() { result = "Pattern" }
21+
22+
/** Gets the module enclosing this pattern */
23+
Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
24+
25+
/** Whether the parenthesized property of this expression is true. */
26+
predicate isParenthesized() { Pattern_.super.isParenthesised() }
27+
28+
override Location getLocation() { result = Pattern_.super.getLocation() }
29+
30+
/** Gets an immediate (non-nested) sub-expression of this pattern */
31+
Expr getASubExpression() { none() }
32+
33+
/** Gets an immediate (non-nested) sub-statement of this pattern */
34+
Stmt getASubStatement() { none() }
35+
36+
/** Gets an immediate (non-nested) sub-pattern of this pattern */
37+
Pattern getASubPattern() { none() }
38+
39+
override AstNode getAChildNode() {
40+
result = this.getASubExpression()
41+
or
42+
result = this.getASubStatement()
43+
or
44+
result = this.getASubPattern()
45+
}
46+
}
47+
48+
/** An as-pattern in a match statement: `<subpattern> as alias` */
49+
class MatchAsPattern extends MatchAsPattern_ {
50+
override Pattern getASubPattern() { result = this.getPattern() }
51+
52+
override Expr getASubExpression() { result = this.getAlias() }
53+
54+
override Name getAlias() { result = super.getAlias() }
55+
}
56+
57+
/** An or-pattern in a match statement: `(<pattern1>|<pattern2>)` */
58+
class MatchOrPattern extends MatchOrPattern_ {
59+
override Pattern getASubPattern() { result = this.getAPattern() }
60+
}
61+
62+
/** A literal pattern in a match statement: `42` */
63+
class MatchLiteralPattern extends MatchLiteralPattern_ {
64+
override Expr getASubExpression() { result = this.getLiteral() }
65+
}
66+
67+
/** A capture pattern in a match statement: `var` */
68+
class MatchCapturePattern extends MatchCapturePattern_ {
69+
/* syntax: varname */
70+
override Expr getASubExpression() { result = this.getVariable() }
71+
72+
/** Gets the variable that is bound by this capture pattern */
73+
override Name getVariable() { result = super.getVariable() }
74+
}
75+
76+
/** A wildcard pattern in a match statement: `_` */
77+
class MatchWildcardPattern extends MatchWildcardPattern_ { }
78+
79+
/** A value pattern in a match statement: `Http.OK` */
80+
class MatchValuePattern extends MatchValuePattern_ {
81+
override Expr getASubExpression() { result = this.getValue() }
82+
}
83+
84+
/** A sequence pattern in a match statement `<p1>, <p2>` */
85+
class MatchSequencePattern extends MatchSequencePattern_ {
86+
override Pattern getASubPattern() { result = this.getAPattern() }
87+
}
88+
89+
/** A star pattern in a match statement: `(..., *)` */
90+
class MatchStarPattern extends MatchStarPattern_ {
91+
override Pattern getASubPattern() { result = this.getTarget() }
92+
}
93+
94+
/** A mapping pattern in a match statement: `{'a': var}` */
95+
class MatchMappingPattern extends MatchMappingPattern_ {
96+
override Pattern getASubPattern() { result = this.getAMapping() }
97+
}
98+
99+
/** A double star pattern in a match statement: `{..., **}` */
100+
class MatchDoubleStarPattern extends MatchDoubleStarPattern_ {
101+
override Pattern getASubPattern() { result = this.getTarget() }
102+
}
103+
104+
/** A key-value pattern inside a mapping pattern: `a: var` */
105+
class MatchKeyValuePattern extends MatchKeyValuePattern_ {
106+
override Pattern getASubPattern() { result = this.getKey() or result = this.getValue() }
107+
}
108+
109+
/** A class pattern in a match statement: `Circle(radius = 3)` */
110+
class MatchClassPattern extends MatchClassPattern_ {
111+
override Expr getASubExpression() { result = this.getClassName() }
112+
113+
override Pattern getASubPattern() {
114+
result = this.getAPositional() or result = this.getAKeyword()
115+
}
116+
}
117+
118+
/** A keyword pattern inside a class pattern: `radius = 3` */
119+
class MatchKeywordPattern extends MatchKeywordPattern_ {
120+
override Expr getASubExpression() { result = this.getAttribute() }
121+
122+
override Pattern getASubPattern() { result = this.getValue() }
123+
}

python/ql/lib/semmle/python/Stmts.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@ class Stmt extends Stmt_, AstNode {
1818
/** Gets an immediate (non-nested) sub-statement of this statement */
1919
Stmt getASubStatement() { none() }
2020

21+
/** Gets an immediate (non-nested) sub-pattern of this statement */
22+
Pattern getASubPattern() { none() }
23+
2124
override AstNode getAChildNode() {
2225
result = this.getASubExpression()
2326
or
2427
result = this.getASubStatement()
28+
or
29+
result = this.getASubPattern()
2530
}
2631

2732
private ControlFlowNode possibleEntryNode() {
@@ -412,6 +417,24 @@ class With extends With_ {
412417
override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() }
413418
}
414419

420+
/** A match statement */
421+
class MatchStmt extends MatchStmt_ {
422+
/* syntax: match subject: */
423+
override Expr getASubExpression() { result = this.getSubject() }
424+
425+
override Stmt getASubStatement() { result = this.getCase(_) }
426+
}
427+
428+
/** A case statement */
429+
class Case extends Case_ {
430+
/* syntax: case pattern if guard: */
431+
override Expr getASubExpression() { result = this.getGuard() }
432+
433+
override Stmt getASubStatement() { result = this.getStmt(_) }
434+
435+
override Pattern getASubPattern() { result = this.getPattern() }
436+
}
437+
415438
/** A plain text used in a template is wrapped in a TemplateWrite statement */
416439
class TemplateWrite extends TemplateWrite_ {
417440
override Expr getASubExpression() { result = this.getValue() }

0 commit comments

Comments
 (0)