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
This commit is contained in:
Rasmus Lerchedahl Petersen
2022-01-18 14:48:46 +01:00
parent b17f844f35
commit de8ecb214f
5 changed files with 162 additions and 0 deletions

View File

@@ -82,6 +82,12 @@ library class StrListParent extends StrListParent_ { }
/** Internal implementation class */
library class ExprParent extends ExprParent_ { }
/** Internal implementation class */
library class PatternListParent extends PatternListParent_ { }
/** Internal implementation class */
library class PatternParent extends PatternParent_ { }
library class DictItem extends DictItem_, AstNode {
override string toString() { result = DictItem_.super.toString() }
@@ -162,6 +168,9 @@ class ExprList extends ExprList_ {
/* syntax: Expr, ... */
}
/** A list of patterns */
class PatternList extends PatternList_ { }
library class DictItemList extends DictItemList_ { }
library class DictItemListParent extends DictItemListParent_ { }

View File

@@ -718,6 +718,12 @@ class FormattedValue extends FormattedValue_ {
}
}
/** A guard in a case statement */
class Guard extends Guard_ {
/* syntax: if Expr */
override Expr getASubExpression() { result = this.getTest() }
}
/* Expression Contexts */
/** A context in which an expression used */
class ExprContext extends ExprContext_ { }

View File

@@ -0,0 +1,123 @@
/**
* Wrapping generated AST classes: `Pattern_` and subclasses.
*/
import python
/** A pattern in a match statement */
class Pattern extends Pattern_, AstNode {
/** Gets the scope of this pattern */
override Scope getScope() {
// TODO: Should it be defined as
// py_scopes(this, result)
// instead?
result = this.getCase().getScope()
}
/** Gets the case statement containing this pattern */
Case getCase() { result.contains(this) }
override string toString() { result = "Pattern" }
/** Gets the module enclosing this pattern */
Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
/** Whether the parenthesized property of this expression is true. */
predicate isParenthesized() { Pattern_.super.isParenthesised() }
override Location getLocation() { result = Pattern_.super.getLocation() }
/** Gets an immediate (non-nested) sub-expression of this pattern */
Expr getASubExpression() { none() }
/** Gets an immediate (non-nested) sub-statement of this pattern */
Stmt getASubStatement() { none() }
/** Gets an immediate (non-nested) sub-pattern of this pattern */
Pattern getASubPattern() { none() }
override AstNode getAChildNode() {
result = this.getASubExpression()
or
result = this.getASubStatement()
or
result = this.getASubPattern()
}
}
/** An as-pattern in a match statement: `<subpattern> as alias` */
class MatchAsPattern extends MatchAsPattern_ {
override Pattern getASubPattern() { result = this.getPattern() }
override Expr getASubExpression() { result = this.getAlias() }
override Name getAlias() { result = super.getAlias() }
}
/** An or-pattern in a match statement: `(<pattern1>|<pattern2>)` */
class MatchOrPattern extends MatchOrPattern_ {
override Pattern getASubPattern() { result = this.getAPattern() }
}
/** A literal pattern in a match statement: `42` */
class MatchLiteralPattern extends MatchLiteralPattern_ {
override Expr getASubExpression() { result = this.getLiteral() }
}
/** A capture pattern in a match statement: `var` */
class MatchCapturePattern extends MatchCapturePattern_ {
/* syntax: varname */
override Expr getASubExpression() { result = this.getVariable() }
/** Gets the variable that is bound by this capture pattern */
override Name getVariable() { result = super.getVariable() }
}
/** A wildcard pattern in a match statement: `_` */
class MatchWildcardPattern extends MatchWildcardPattern_ { }
/** A value pattern in a match statement: `Http.OK` */
class MatchValuePattern extends MatchValuePattern_ {
override Expr getASubExpression() { result = this.getValue() }
}
/** A sequence pattern in a match statement `<p1>, <p2>` */
class MatchSequencePattern extends MatchSequencePattern_ {
override Pattern getASubPattern() { result = this.getAPattern() }
}
/** A star pattern in a match statement: `(..., *)` */
class MatchStarPattern extends MatchStarPattern_ {
override Pattern getASubPattern() { result = this.getTarget() }
}
/** A mapping pattern in a match statement: `{'a': var}` */
class MatchMappingPattern extends MatchMappingPattern_ {
override Pattern getASubPattern() { result = this.getAMapping() }
}
/** A double star pattern in a match statement: `{..., **}` */
class MatchDoubleStarPattern extends MatchDoubleStarPattern_ {
override Pattern getASubPattern() { result = this.getTarget() }
}
/** A key-value pattern inside a mapping pattern: `a: var` */
class MatchKeyValuePattern extends MatchKeyValuePattern_ {
override Pattern getASubPattern() { result = this.getKey() or result = this.getValue() }
}
/** A class pattern in a match statement: `Circle(radius = 3)` */
class MatchClassPattern extends MatchClassPattern_ {
override Expr getASubExpression() { result = this.getClassName() }
override Pattern getASubPattern() {
result = this.getAPositional() or result = this.getAKeyword()
}
}
/** A keyword pattern inside a class pattern: `radius = 3` */
class MatchKeywordPattern extends MatchKeywordPattern_ {
override Expr getASubExpression() { result = this.getAttribute() }
override Pattern getASubPattern() { result = this.getValue() }
}

View File

@@ -18,10 +18,15 @@ class Stmt extends Stmt_, AstNode {
/** 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() {
@@ -412,6 +417,24 @@ class With extends With_ {
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() }