Skip to content

Commit

Permalink
C#: Introduce a class for ref structs.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelnebel committed Jan 3, 2025
1 parent 20c23bb commit a358617
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
2 changes: 1 addition & 1 deletion csharp/ql/lib/semmle/code/csharp/Conversion.qll
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ private predicate convBoxingValueType(ValueType fromType, Type toType) {
or
toType instanceof SystemValueTypeClass
) and
not fromType.(Struct).isRef()
not fromType.isRefLikeType()
or
toType = fromType.getABaseInterface+()
}
Expand Down
32 changes: 30 additions & 2 deletions csharp/ql/lib/semmle/code/csharp/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ class Type extends Member, TypeContainer, @type {

/** Holds if this type is a value type, or a type parameter that is a value type. */
predicate isValueType() { none() }

/**
* Holds if this type is a ref like type, or a type parameter that is a ref like type.
*/
predicate isRefLikeType() { none() }
}

pragma[nomagic]
Expand Down Expand Up @@ -704,15 +709,38 @@ class Enum extends ValueType, @enum_type {
* ```
*/
class Struct extends ValueType, @struct_type {
/** Holds if this `struct` has a `ref` modifier. */
predicate isRef() { this.hasModifier("ref") }
/**
* DEPRECATED: Use `instanceof RefStruct` instead.
*
* Holds if this `struct` has a `ref` modifier.
*/
deprecated predicate isRef() { this.hasModifier("ref") }

/** Holds if this `struct` has a `readonly` modifier. */
predicate isReadonly() { this.hasModifier("readonly") }

override string getAPrimaryQlClass() { result = "Struct" }
}

/**
* A `ref struct`, for example
*
* ```csharp
* ref struct S {
* ...
* }
* ```
*/
class RefStruct extends Struct {
RefStruct() { this.hasModifier("ref") }

override string getAPrimaryQlClass() { result = "RefStruct" }

override predicate isValueType() { none() }

override predicate isRefLikeType() { any() }
}

/**
* A `record struct`, for example
* ```csharp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ module LocalFlow {
or
t = any(TypeParameter tp | not tp.isValueType())
or
t.(Struct).isRef()
t.isRefLikeType()
) and
not exists(getALastEvalNode(result))
}
Expand Down

0 comments on commit a358617

Please sign in to comment.