Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/EnumImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,23 @@ module Impl {
result = this.getVariantList().getAVariant() and
result.getName().getText() = name
}

/**
* Holds if this is a field-less enum, that is, an enum where no constructors contain fields.
*
* See: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.fieldless
*/
predicate isFieldless() {
forall(Variant v | v = this.getVariantList().getAVariant() | v.getNumberOfFields() = 0)
}

/**
* Holds if this is a unit-only enum, that is, an enum where all constructors are unit variants.
*
* See: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.unit-only
*/
predicate isUnitOnly() {
forall(Variant v | v = this.getVariantList().getAVariant() | v.isUnit())
}
}
}
11 changes: 5 additions & 6 deletions rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,11 @@ module Impl {
pragma[nomagic]
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }

/**
* Holds if this struct uses record fields.
*
* Empty structs are considered to use record fields.
*/
/** Holds if this struct uses struct fields. */
pragma[nomagic]
predicate isStruct() { not this.isTuple() }
predicate isStruct() { this.getFieldList() instanceof StructFieldList }

/** Holds if this struct does not have a field list. */
predicate isUnit() { not this.hasFieldList() }
}
}
22 changes: 16 additions & 6 deletions rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,27 @@ module Impl {
pragma[nomagic]
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }

/** Gets the number of fields of this variant. */
int getNumberOfFields() {
not this.hasFieldList() and
result = 0
or
result = this.getFieldList().(StructFieldList).getNumberOfFields()
or
result = this.getFieldList().(TupleFieldList).getNumberOfFields()
}

/** Holds if this variant uses tuple fields. */
pragma[nomagic]
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }

/**
* Holds if this variant uses struct fields.
*
* Empty variants are considered to use struct fields.
*/
/** Holds if this variant uses struct fields. */
pragma[nomagic]
predicate isStruct() { this.getFieldList() instanceof StructFieldList }

/** Holds if this variant does not have a field list. */
pragma[nomagic]
predicate isStruct() { not this.isTuple() }
predicate isUnit() { not this.hasFieldList() }

/** Gets the enum that this variant belongs to. */
Enum getEnum() { this = result.getVariantList().getAVariant() }
Expand Down
4 changes: 2 additions & 2 deletions rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ private class VariantItemNode extends ParameterizableItemNode instanceof Variant
override string getName() { result = Variant.super.getName().getText() }

override Namespace getNamespace() {
if super.getFieldList() instanceof StructFieldList then result.isType() else result.isValue()
if super.isStruct() then result.isType() else result.isValue()
}

override TypeParam getTypeParam(int i) {
Expand Down Expand Up @@ -969,7 +969,7 @@ private class StructItemNode extends TypeItemNode, ParameterizableItemNode insta
override Namespace getNamespace() {
result.isType() // the struct itself
or
not super.getFieldList() instanceof StructFieldList and
not super.isStruct() and
result.isValue() // the constructor
}

Expand Down
4 changes: 2 additions & 2 deletions rust/ql/lib/codeql/rust/internal/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
}

private class StructDecl extends Declaration, Struct {
StructDecl() { this.isStruct() }
StructDecl() { this.isStruct() or this.isUnit() }

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

Expand All @@ -804,7 +804,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
}

private class StructVariantDecl extends Declaration, Variant {
StructVariantDecl() { this.isStruct() }
StructVariantDecl() { this.isStruct() or this.isUnit() }

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

Expand Down
7 changes: 7 additions & 0 deletions rust/ql/test/library-tests/elements/enum/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions rust/ql/test/library-tests/elements/enum/Enum.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fieldless
| enums.rs:1:1:5:1 | enum Foo |
| enums.rs:7:1:11:1 | enum Fieldless |
| enums.rs:13:1:18:1 | enum Direction |
unitOnly
| enums.rs:1:1:5:1 | enum Foo |
| enums.rs:13:1:18:1 | enum Direction |
6 changes: 6 additions & 0 deletions rust/ql/test/library-tests/elements/enum/Enum.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import rust
import TestUtils

query predicate fieldless(Enum e) { toBeTested(e) and e.isFieldless() }

query predicate unitOnly(Enum e) { toBeTested(e) and e.isUnitOnly() }
24 changes: 24 additions & 0 deletions rust/ql/test/library-tests/elements/enum/enums.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
enum Foo {
Bar,
Baz,
Qux,
}

enum Fieldless {
Tuple(),
Struct{},
Unit,
}

enum Direction {
North = 0,
East = 90,
South = 180,
West = 270,
}

enum Color {
Red(u8),
Green(u8),
Blue(u8),
}