Skip to content

Commit 1c8cc39

Browse files
authored
Merge pull request #20906 from paldepind/rust/enum-fieldless
Rust: Add predicates for fieldless and unit-only enums
2 parents 0414555 + 4f13ae3 commit 1c8cc39

File tree

9 files changed

+87
-16
lines changed

9 files changed

+87
-16
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,23 @@ module Impl {
3131
result = this.getVariantList().getAVariant() and
3232
result.getName().getText() = name
3333
}
34+
35+
/**
36+
* Holds if this is a field-less enum, that is, an enum where no constructors contain fields.
37+
*
38+
* See: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.fieldless
39+
*/
40+
predicate isFieldless() {
41+
forall(Variant v | v = this.getVariantList().getAVariant() | v.getNumberOfFields() = 0)
42+
}
43+
44+
/**
45+
* Holds if this is a unit-only enum, that is, an enum where all constructors are unit variants.
46+
*
47+
* See: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.unit-only
48+
*/
49+
predicate isUnitOnly() {
50+
forall(Variant v | v = this.getVariantList().getAVariant() | v.isUnit())
51+
}
3452
}
3553
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,11 @@ module Impl {
4646
pragma[nomagic]
4747
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }
4848

49-
/**
50-
* Holds if this struct uses record fields.
51-
*
52-
* Empty structs are considered to use record fields.
53-
*/
49+
/** Holds if this struct uses struct fields. */
5450
pragma[nomagic]
55-
predicate isStruct() { not this.isTuple() }
51+
predicate isStruct() { this.getFieldList() instanceof StructFieldList }
52+
53+
/** Holds if this struct does not have a field list. */
54+
predicate isUnit() { not this.hasFieldList() }
5655
}
5756
}

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,27 @@ module Impl {
3636
pragma[nomagic]
3737
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }
3838

39+
/** Gets the number of fields of this variant. */
40+
int getNumberOfFields() {
41+
not this.hasFieldList() and
42+
result = 0
43+
or
44+
result = this.getFieldList().(StructFieldList).getNumberOfFields()
45+
or
46+
result = this.getFieldList().(TupleFieldList).getNumberOfFields()
47+
}
48+
3949
/** Holds if this variant uses tuple fields. */
4050
pragma[nomagic]
4151
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }
4252

43-
/**
44-
* Holds if this variant uses struct fields.
45-
*
46-
* Empty variants are considered to use struct fields.
47-
*/
53+
/** Holds if this variant uses struct fields. */
54+
pragma[nomagic]
55+
predicate isStruct() { this.getFieldList() instanceof StructFieldList }
56+
57+
/** Holds if this variant does not have a field list. */
4858
pragma[nomagic]
49-
predicate isStruct() { not this.isTuple() }
59+
predicate isUnit() { not this.hasFieldList() }
5060

5161
/** Gets the enum that this variant belongs to. */
5262
Enum getEnum() { this = result.getVariantList().getAVariant() }

rust/ql/lib/codeql/rust/internal/PathResolution.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ private class VariantItemNode extends ParameterizableItemNode instanceof Variant
659659
override string getName() { result = Variant.super.getName().getText() }
660660

661661
override Namespace getNamespace() {
662-
if super.getFieldList() instanceof StructFieldList then result.isType() else result.isValue()
662+
if super.isStruct() then result.isType() else result.isValue()
663663
}
664664

665665
override TypeParam getTypeParam(int i) {
@@ -969,7 +969,7 @@ private class StructItemNode extends TypeItemNode, ParameterizableItemNode insta
969969
override Namespace getNamespace() {
970970
result.isType() // the struct itself
971971
or
972-
not super.getFieldList() instanceof StructFieldList and
972+
not super.isStruct() and
973973
result.isValue() // the constructor
974974
}
975975

rust/ql/lib/codeql/rust/internal/TypeInference.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
787787
}
788788

789789
private class StructDecl extends Declaration, Struct {
790-
StructDecl() { this.isStruct() }
790+
StructDecl() { this.isStruct() or this.isUnit() }
791791

792792
override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() }
793793

@@ -804,7 +804,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
804804
}
805805

806806
private class StructVariantDecl extends Declaration, Variant {
807-
StructVariantDecl() { this.isStruct() }
807+
StructVariantDecl() { this.isStruct() or this.isUnit() }
808808

809809
Enum getEnum() { result.getVariantList().getAVariant() = this }
810810

rust/ql/test/library-tests/elements/enum/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fieldless
2+
| enums.rs:1:1:5:1 | enum Foo |
3+
| enums.rs:7:1:11:1 | enum Fieldless |
4+
| enums.rs:13:1:18:1 | enum Direction |
5+
unitOnly
6+
| enums.rs:1:1:5:1 | enum Foo |
7+
| enums.rs:13:1:18:1 | enum Direction |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import rust
2+
import TestUtils
3+
4+
query predicate fieldless(Enum e) { toBeTested(e) and e.isFieldless() }
5+
6+
query predicate unitOnly(Enum e) { toBeTested(e) and e.isUnitOnly() }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
enum Foo {
2+
Bar,
3+
Baz,
4+
Qux,
5+
}
6+
7+
enum Fieldless {
8+
Tuple(),
9+
Struct{},
10+
Unit,
11+
}
12+
13+
enum Direction {
14+
North = 0,
15+
East = 90,
16+
South = 180,
17+
West = 270,
18+
}
19+
20+
enum Color {
21+
Red(u8),
22+
Green(u8),
23+
Blue(u8),
24+
}

0 commit comments

Comments
 (0)