Skip to content

Commit 8f886c6

Browse files
authored
Merge pull request #18088 from paldepind/rust-self-parameters
Rust: Handle `self` parameters in variables and SSA library
2 parents 553bc8c + 7ab5663 commit 8f886c6

File tree

9 files changed

+310
-268
lines changed

9 files changed

+310
-268
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/dataflow/internal/SsaImpl.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ predicate variableWrite(AstNode write, Variable v) {
2424
not isUnitializedLet(pat, v)
2525
)
2626
or
27+
exists(SelfParam self | self = write and self = v.getSelfParam())
28+
or
2729
exists(VariableAccess access |
2830
access = write and
2931
access.getVariable() = v
@@ -477,7 +479,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
477479
none() // handled in `DataFlowImpl.qll` instead
478480
}
479481

480-
class Parameter = CfgNodes::ParamCfgNode;
482+
class Parameter = CfgNodes::ParamBaseCfgNode;
481483

482484
/** Holds if SSA definition `def` initializes parameter `p` at function entry. */
483485
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) {

rust/ql/lib/codeql/rust/elements/internal/ParamListImpl.qll

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// generated by codegen, remove this comment if you wish to edit this file
21
/**
32
* This module provides a hand-modifiable wrapper around the generated class `ParamList`.
43
*
@@ -12,11 +11,17 @@ private import codeql.rust.elements.internal.generated.ParamList
1211
* be referenced directly.
1312
*/
1413
module Impl {
14+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1515
/**
1616
* A ParamList. For example:
1717
* ```rust
1818
* todo!()
1919
* ```
2020
*/
21-
class ParamList extends Generated::ParamList { }
21+
class ParamList extends Generated::ParamList {
22+
/**
23+
* Gets any of the parameters of this parameter list.
24+
*/
25+
final ParamBase getAParamBase() { result = this.getParam(_) or result = this.getSelfParam() }
26+
}
2227
}

rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -73,24 +73,35 @@ module Impl {
7373
* where `definingNode` is the entire `Either::Left(x) | Either::Right(x)`
7474
* pattern.
7575
*/
76-
private predicate variableDecl(AstNode definingNode, IdentPat p, string name) {
77-
(
78-
definingNode = getOutermostEnclosingOrPat(p)
79-
or
80-
not exists(getOutermostEnclosingOrPat(p)) and
81-
definingNode = p.getName()
82-
) and
83-
name = p.getName().getText() and
84-
// exclude for now anything starting with an uppercase character, which may be a reference to
85-
// an enum constant (e.g. `None`). This excludes static and constant variables (UPPERCASE),
86-
// which we don't appear to recognize yet anyway. This also assumes programmers follow the
87-
// naming guidelines, which they generally do, but they're not enforced.
88-
not name.charAt(0).isUppercase() and
89-
// exclude parameters from functions without a body as these are trait method declarations
90-
// without implementations
91-
not exists(Function f | not f.hasBody() and f.getParamList().getAParam().getPat() = p) and
92-
// exclude parameters from function pointer types (e.g. `x` in `fn(x: i32) -> i32`)
93-
not exists(FnPtrType fp | fp.getParamList().getParam(_).getPat() = p)
76+
private predicate variableDecl(AstNode definingNode, AstNode p, string name) {
77+
p =
78+
any(SelfParam sp |
79+
definingNode = sp.getName() and
80+
name = sp.getName().getText() and
81+
// exclude self parameters from functions without a body as these are
82+
// trait method declarations without implementations
83+
not exists(Function f | not f.hasBody() and f.getParamList().getSelfParam() = sp)
84+
)
85+
or
86+
p =
87+
any(IdentPat pat |
88+
(
89+
definingNode = getOutermostEnclosingOrPat(pat)
90+
or
91+
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = pat.getName()
92+
) and
93+
name = pat.getName().getText() and
94+
// exclude for now anything starting with an uppercase character, which may be a reference to
95+
// an enum constant (e.g. `None`). This excludes static and constant variables (UPPERCASE),
96+
// which we don't appear to recognize yet anyway. This also assumes programmers follow the
97+
// naming guidelines, which they generally do, but they're not enforced.
98+
not name.charAt(0).isUppercase() and
99+
// exclude parameters from functions without a body as these are trait method declarations
100+
// without implementations
101+
not exists(Function f | not f.hasBody() and f.getParamList().getAParam().getPat() = pat) and
102+
// exclude parameters from function pointer types (e.g. `x` in `fn(x: i32) -> i32`)
103+
not exists(FnPtrType fp | fp.getParamList().getParam(_).getPat() = pat)
104+
)
94105
}
95106

96107
/** A variable. */
@@ -112,8 +123,11 @@ module Impl {
112123
/** Gets an access to this variable. */
113124
VariableAccess getAnAccess() { result.getVariable() = this }
114125

126+
/** Gets the `self` parameter that declares this variable, if one exists. */
127+
SelfParam getSelfParam() { variableDecl(definingNode, result, name) }
128+
115129
/**
116-
* Gets the pattern that declares this variable.
130+
* Gets the pattern that declares this variable, if any.
117131
*
118132
* Normally, the pattern is unique, except when introduced in an or pattern:
119133
*
@@ -135,7 +149,9 @@ module Impl {
135149
predicate isCaptured() { this.getAnAccess().isCapture() }
136150

137151
/** Gets the parameter that introduces this variable, if any. */
138-
Param getParameter() { parameterDeclInScope(result, this, _) }
152+
ParamBase getParameter() {
153+
result = this.getSelfParam() or result.(Param).getPat() = getAVariablePatAncestor(this)
154+
}
139155

140156
/** Hold is this variable is mutable. */
141157
predicate isMutable() { this.getPat().isMut() }
@@ -144,7 +160,11 @@ module Impl {
144160
predicate isImmutable() { not this.isMutable() }
145161
}
146162

147-
/** A path expression that may access a local variable. */
163+
/**
164+
* A path expression that may access a local variable. These are paths that
165+
* only consists of a simple name (i.e., without generic arguments,
166+
* qualifiers, etc.).
167+
*/
148168
private class VariableAccessCand extends PathExprBase {
149169
string name_;
150170

@@ -190,10 +210,7 @@ module Impl {
190210
private VariableScope getEnclosingScope(AstNode n) { result = getAnAncestorInVariableScope(n) }
191211

192212
private Pat getAVariablePatAncestor(Variable v) {
193-
exists(AstNode definingNode, string name |
194-
v = MkVariable(definingNode, name) and
195-
variableDecl(definingNode, result, name)
196-
)
213+
result = v.getPat()
197214
or
198215
exists(Pat mid |
199216
mid = getAVariablePatAncestor(v) and
@@ -202,23 +219,12 @@ module Impl {
202219
}
203220

204221
/**
205-
* Holds if parameter `p` introduces the variable `v` inside variable scope
206-
* `scope`.
222+
* Holds if a parameter declares the variable `v` inside variable scope `scope`.
207223
*/
208-
private predicate parameterDeclInScope(Param p, Variable v, VariableScope scope) {
209-
exists(Pat pat |
210-
pat = getAVariablePatAncestor(v) and
211-
p.getPat() = pat
212-
|
213-
exists(Function f |
214-
f.getParamList().getAParam() = p and
215-
scope = f.getBody()
216-
)
217-
or
218-
exists(ClosureExpr ce |
219-
ce.getParamList().getAParam() = p and
220-
scope = ce.getBody()
221-
)
224+
private predicate parameterDeclInScope(Variable v, VariableScope scope) {
225+
exists(Callable f |
226+
v.getParameter() = f.getParamList().getAParamBase() and
227+
scope = [f.(Function).getBody(), f.(ClosureExpr).getBody()]
222228
)
223229
}
224230

@@ -231,7 +237,7 @@ module Impl {
231237
) {
232238
name = v.getName() and
233239
(
234-
parameterDeclInScope(_, v, scope) and
240+
parameterDeclInScope(v, scope) and
235241
scope.getLocation().hasLocationFileInfo(_, line, column, _, _)
236242
or
237243
exists(Pat pat | pat = getAVariablePatAncestor(v) |

0 commit comments

Comments
 (0)