Skip to content

Commit 2f14ec9

Browse files
committed
Rust: Include patterns in the CFG
1 parent f6f54c6 commit 2f14ec9

File tree

9 files changed

+504
-183
lines changed

9 files changed

+504
-183
lines changed

rust/ql/.generated.list

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/.gitattributes

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ abstract class ConditionalCompletion extends NormalCompletion {
6262
abstract ConditionalCompletion getDual();
6363
}
6464

65-
/** Holds if node `le` has the Boolean constant value `value`. */
65+
/** Holds if node `le` has the constant Boolean value `value`. */
6666
private predicate isBooleanConstant(LiteralExpr le, Boolean value) {
6767
le.getTextValue() = value.toString()
6868
}
@@ -117,13 +117,61 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
117117
override string toString() { result = "boolean(" + value + ")" }
118118
}
119119

120+
/** Holds if node `pat` has the constant match value `value`. */
121+
pragma[nomagic]
122+
private predicate isMatchConstant(Pat pat, boolean value) {
123+
value = true and
124+
(
125+
pat instanceof WildcardPat
126+
or
127+
pat = any(IdentPat ip | not ip.hasPat() and ip = any(Variable v).getPat())
128+
or
129+
pat instanceof RestPat
130+
or
131+
// `let` statements without an `else` branch must be exhaustive
132+
pat = any(LetStmt let | not let.hasLetElse()).getPat()
133+
or
134+
// `match` expressions must be exhaustive, so last arm cannot fail
135+
pat = any(MatchExpr me).getLastArm().getPat()
136+
or
137+
// parameter patterns must be exhaustive
138+
pat = any(Param p).getPat()
139+
) and
140+
not pat = any(ForExpr for).getPat() // workaround until `for` loops are desugared
141+
or
142+
exists(Pat parent | isMatchConstant(parent, value) |
143+
pat = parent.(BoxPat).getPat()
144+
or
145+
pat = parent.(IdentPat).getPat()
146+
or
147+
pat = parent.(ParenPat).getPat()
148+
or
149+
pat = parent.(RecordPat).getRecordPatFieldList().getField(_).getPat()
150+
or
151+
pat = parent.(RefPat).getPat()
152+
or
153+
pat = parent.(TuplePat).getAField()
154+
or
155+
pat = parent.(TupleStructPat).getAField()
156+
or
157+
pat = parent.(OrPat).getLastPat()
158+
)
159+
}
160+
120161
/**
121162
* A completion that represents the result of a pattern match.
122163
*/
123164
class MatchCompletion extends TMatchCompletion, ConditionalCompletion {
124165
MatchCompletion() { this = TMatchCompletion(value) }
125166

126-
override predicate isValidForSpecific(AstNode e) { e instanceof Pat }
167+
override predicate isValidForSpecific(AstNode e) {
168+
e instanceof Pat and
169+
(
170+
isMatchConstant(e, value)
171+
or
172+
not isMatchConstant(e, _)
173+
)
174+
}
127175

128176
override MatchSuccessor getAMatchingSuccessorType() { result.getValue() = value }
129177

0 commit comments

Comments
 (0)