Skip to content

Commit 707bf16

Browse files
committed
Rust: Shorthand record construction in data flow
1 parent 9bc3b0e commit 707bf16

File tree

12 files changed

+89
-20
lines changed

12 files changed

+89
-20
lines changed

rust/ql/lib/codeql/rust/controlflow/CfgNodes.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ final class RecordExprCfgNode extends Nodes::RecordExprCfgNode {
241241
exists(RecordExprField ref |
242242
ref = node.getRecordExprFieldList().getAField() and
243243
any(ChildMapping mapping).hasCfgChild(node, ref.getExpr(), this, result) and
244-
field = ref.getNameRef().getText()
244+
field = ref.getFieldName()
245245
)
246246
}
247247
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,24 @@ module Impl {
3434
pragma[nomagic]
3535
string getText() { result = this.getPart().getNameRef().getText() }
3636
}
37+
38+
/** A simple identifier path. */
39+
class IdentPath extends Path {
40+
private string name;
41+
42+
IdentPath() {
43+
not this.hasQualifier() and
44+
exists(PathSegment ps |
45+
ps = this.getPart() and
46+
not ps.hasGenericArgList() and
47+
not ps.hasParenthesizedArgList() and
48+
not ps.hasPathType() and
49+
not ps.hasReturnTypeSyntax() and
50+
name = ps.getNameRef().getText()
51+
)
52+
}
53+
54+
/** Gets the identifier name. */
55+
string getName() { result = name }
56+
}
3757
}

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ private import codeql.rust.elements.internal.generated.RecordExprField
1111
* be referenced directly.
1212
*/
1313
module Impl {
14+
private import rust
15+
private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl
16+
1417
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1518
/**
1619
* A field in a record expression. For example `a: 1` in:
@@ -24,7 +27,27 @@ module Impl {
2427
private string toStringPart(int index) {
2528
index = 0 and result = this.getNameRef().getText()
2629
or
27-
index = 1 and result = ": " + this.getExpr().toAbbreviatedString()
30+
index = 1 and this.hasNameRef() and result = ": "
31+
or
32+
index = 2 and
33+
result = this.getExpr().toAbbreviatedString()
34+
}
35+
36+
/**
37+
* Gets the name of the field. This includes the case when shorthand syntax is used:
38+
*
39+
* ```rust
40+
* Foo {
41+
* a: 1, // field name is `a`
42+
* b // field name is `b`
43+
* }
44+
* ```
45+
*/
46+
string getFieldName() {
47+
result = this.getNameRef().getText()
48+
or
49+
not this.hasNameRef() and
50+
result = this.getExpr().(PathExpr).getPath().(PathImpl::IdentPath).getName()
2851
}
2952
}
3053
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module Impl {
3232
RecordField getRecordField(string name) {
3333
exists(PathResolution::ItemNode i |
3434
i = PathResolution::resolvePath(this.getPath()) and
35-
name = this.getRecordExprFieldList().getAField().getNameRef().getText()
35+
name = this.getRecordExprFieldList().getAField().getFieldName()
3636
|
3737
result.isStructField(i, name) or
3838
result.isVariantField(i, name)

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ module Impl {
2121
* ```
2222
*/
2323
class RecordPatField extends Generated::RecordPatField {
24+
override string toString() { result = concat(int i | | this.toStringPart(i) order by i) }
25+
26+
private string toStringPart(int index) {
27+
index = 0 and result = this.getNameRef().getText()
28+
or
29+
index = 1 and this.hasNameRef() and result = ": "
30+
or
31+
index = 2 and
32+
result = this.getPat().toAbbreviatedString()
33+
}
34+
2435
/**
2536
* Gets the name of the field. This includes the case when shorthand syntax is used:
2637
*

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
private import rust
22
private import codeql.rust.controlflow.ControlFlowGraph
33
private import codeql.rust.elements.internal.generated.ParentChild
4+
private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl
45
private import codeql.rust.elements.internal.PathExprBaseImpl::Impl as PathExprBaseImpl
56
private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl::Impl as FormatTemplateVariableAccessImpl
67
private import codeql.util.DenseRank
@@ -172,16 +173,7 @@ module Impl {
172173
string name_;
173174

174175
VariableAccessCand() {
175-
exists(Path p, PathSegment ps |
176-
p = this.(PathExpr).getPath() and
177-
not p.hasQualifier() and
178-
ps = p.getPart() and
179-
not ps.hasGenericArgList() and
180-
not ps.hasParenthesizedArgList() and
181-
not ps.hasPathType() and
182-
not ps.hasReturnTypeSyntax() and
183-
name_ = ps.getNameRef().getText()
184-
)
176+
name_ = this.(PathExpr).getPath().(PathImpl::IdentPath).getName()
185177
or
186178
this.(FormatTemplateVariableAccess).getName() = name_
187179
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| gen_record_pat_field.rs:5:15:5:18 | RecordPatField | getNumberOfAttrs: | 0 | hasNameRef: | yes | hasPat: | yes |
2-
| gen_record_pat_field.rs:5:21:5:24 | RecordPatField | getNumberOfAttrs: | 0 | hasNameRef: | yes | hasPat: | yes |
1+
| gen_record_pat_field.rs:5:15:5:18 | a: 1 | getNumberOfAttrs: | 0 | hasNameRef: | yes | hasPat: | yes |
2+
| gen_record_pat_field.rs:5:21:5:24 | b: 2 | getNumberOfAttrs: | 0 | hasNameRef: | yes | hasPat: | yes |
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| gen_record_pat_field.rs:5:15:5:18 | RecordPatField | gen_record_pat_field.rs:5:15:5:15 | a |
2-
| gen_record_pat_field.rs:5:21:5:24 | RecordPatField | gen_record_pat_field.rs:5:21:5:21 | b |
1+
| gen_record_pat_field.rs:5:15:5:18 | a: 1 | gen_record_pat_field.rs:5:15:5:15 | a |
2+
| gen_record_pat_field.rs:5:21:5:24 | b: 2 | gen_record_pat_field.rs:5:21:5:21 | b |
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| gen_record_pat_field.rs:5:15:5:18 | RecordPatField | gen_record_pat_field.rs:5:18:5:18 | 1 |
2-
| gen_record_pat_field.rs:5:21:5:24 | RecordPatField | gen_record_pat_field.rs:5:24:5:24 | 2 |
1+
| gen_record_pat_field.rs:5:15:5:18 | a: 1 | gen_record_pat_field.rs:5:18:5:18 | 1 |
2+
| gen_record_pat_field.rs:5:21:5:24 | b: 2 | gen_record_pat_field.rs:5:24:5:24 | 2 |

rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ storeStep
570570
| main.rs:167:12:167:12 | 4 | Point3D.z | main.rs:162:13:168:5 | Point3D {...} |
571571
| main.rs:177:16:177:32 | Point {...} | Point3D.plane | main.rs:176:13:179:5 | Point3D {...} |
572572
| main.rs:177:27:177:27 | 2 | Point.x | main.rs:177:16:177:32 | Point {...} |
573+
| main.rs:177:30:177:30 | y | Point.y | main.rs:177:16:177:32 | Point {...} |
573574
| main.rs:178:12:178:12 | 4 | Point3D.z | main.rs:176:13:179:5 | Point3D {...} |
574575
| main.rs:195:27:195:36 | source(...) | MyTupleStruct(0) | main.rs:195:13:195:40 | MyTupleStruct(...) |
575576
| main.rs:195:39:195:39 | 2 | MyTupleStruct(1) | main.rs:195:13:195:40 | MyTupleStruct(...) |

0 commit comments

Comments
 (0)