mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
C#: Handle unbound types in conversion library
A constructed type, `C<T>`, where `T` is the type parameter of `C`, is represented in the database as the corresponding unbound generict type `C<>`. Consequently, the type conversion library, which only considers `ConstructedType`s, does not handle all implicit conversions. For example, in ``` interface I<in T1, T2> where T1 : C ``` there should be an implicit conversion from `I<C, T2>` to `I<T1, T2>` (=`I<>`).
This commit is contained in:
@@ -54,11 +54,28 @@ private predicate implicitConversionNonNull(Type fromType, Type toType) {
|
||||
fromType instanceof DynamicType // 6.1.8
|
||||
}
|
||||
|
||||
private Type getTypeArgument(UnboundGenericType ugt, ConstructedType ct, int i, TypeParameter tp) {
|
||||
ct.getUnboundGeneric() = ugt and
|
||||
/**
|
||||
* A generic type. This includes both constructed generic types and unbound
|
||||
* generic types (which correspond to constructed generic types where the
|
||||
* type arguments equal the type parameters).
|
||||
*/
|
||||
private class GenericType extends Generic, Type {
|
||||
/** Gets the `i`th type argument. */
|
||||
Type getTypeArgument(int i) { result = this.getChild(i) }
|
||||
|
||||
/** Gets the unbound generic type. */
|
||||
UnboundGenericType getUnboundGeneric() {
|
||||
result = this.(ConstructedType).getUnboundGeneric()
|
||||
or
|
||||
result = this
|
||||
}
|
||||
}
|
||||
|
||||
private Type getTypeArgument(UnboundGenericType ugt, GenericType gt, int i, TypeParameter tp) {
|
||||
gt.getUnboundGeneric() = ugt and
|
||||
not ugt instanceof AnonymousClass and
|
||||
tp = ugt.getTypeParameter(i) and
|
||||
result = ct.getTypeArgument(i)
|
||||
result = gt.getTypeArgument(i)
|
||||
}
|
||||
|
||||
/** A type that is an element type of an array type. */
|
||||
@@ -68,7 +85,7 @@ private class ArrayElementType extends Type {
|
||||
|
||||
/** A type that is an argument in a constructed type. */
|
||||
private class TypeArgument extends Type {
|
||||
TypeArgument() { this = any(ConstructedType ct).getATypeArgument() }
|
||||
TypeArgument() { this = any(GenericType gt).getTypeArgument(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,8 +112,7 @@ private module Identity {
|
||||
|
||||
private class IdentityConvertibleArrayType extends IdentityConvertibleType, ArrayType { }
|
||||
|
||||
private class IdentityConvertibleConstructedType extends IdentityConvertibleType, ConstructedType {
|
||||
}
|
||||
private class IdentityConvertibleGenericType extends IdentityConvertibleType, GenericType { }
|
||||
|
||||
/**
|
||||
* A type is (strictly) identity convertible if it contains at least one `object`
|
||||
@@ -109,7 +125,7 @@ private module Identity {
|
||||
or
|
||||
isIdentityConvertible(t.(ArrayType).getElementType())
|
||||
or
|
||||
isIdentityConvertible(t.(ConstructedType).getATypeArgument())
|
||||
isIdentityConvertible(t.(GenericType).getTypeArgument(_))
|
||||
}
|
||||
|
||||
predicate convIdentityStrict(IdentityConvertibleType fromType, IdentityConvertibleType toType) {
|
||||
@@ -119,7 +135,7 @@ private module Identity {
|
||||
or
|
||||
convIdentityStrictArrayType(fromType, toType)
|
||||
or
|
||||
convIdentityStrictConstructedType(fromType, toType)
|
||||
convIdentityStrictGenericType(fromType, toType)
|
||||
}
|
||||
|
||||
private predicate convIdentityObjectDynamic(ObjectType fromType, DynamicType toType) { any() }
|
||||
@@ -151,7 +167,7 @@ private module Identity {
|
||||
*/
|
||||
private int getTypeArgumentCount(UnboundGenericType ugt, int i) {
|
||||
result = strictcount(Type arg |
|
||||
exists(IdentityConvertibleConstructedType ct | ct.getUnboundGeneric() = ugt |
|
||||
exists(IdentityConvertibleGenericType ct | ct.getUnboundGeneric() = ugt |
|
||||
arg = ct.getTypeArgument(i)
|
||||
)
|
||||
)
|
||||
@@ -162,9 +178,7 @@ private module Identity {
|
||||
}
|
||||
|
||||
/** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */
|
||||
private Type getTypeArgumentRanked(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType t, int i
|
||||
) {
|
||||
private Type getTypeArgumentRanked(UnboundGenericType ugt, IdentityConvertibleGenericType t, int i) {
|
||||
result = getTypeArgument(ugt, t, rnk(ugt, i), _)
|
||||
}
|
||||
|
||||
@@ -207,8 +221,8 @@ private module Identity {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentitySingle0(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType toType,
|
||||
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType toType, TypeArgument fromTypeArgument,
|
||||
TypeArgument toTypeArgument
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, toType, 0) and
|
||||
@@ -220,8 +234,8 @@ private module Identity {
|
||||
* convertible, and the number of type arguments is 1.
|
||||
*/
|
||||
predicate convIdentitySingle(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
|
||||
IdentityConvertibleConstructedType toType
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType fromType,
|
||||
IdentityConvertibleGenericType toType
|
||||
) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convIdentitySingle0(ugt, toType, fromTypeArgument, toTypeArgument)
|
||||
@@ -232,8 +246,8 @@ private module Identity {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentityMultiple01Aux0(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType toType,
|
||||
TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType toType, TypeArgument fromTypeArgument0,
|
||||
TypeArgument toTypeArgument0, TypeArgument toTypeArgument1
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and
|
||||
toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0) and
|
||||
@@ -242,8 +256,8 @@ private module Identity {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentityMultiple01Aux1(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
|
||||
TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType fromType, TypeArgument fromTypeArgument0,
|
||||
TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and
|
||||
fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0) and
|
||||
@@ -255,8 +269,8 @@ private module Identity {
|
||||
* are identity convertible.
|
||||
*/
|
||||
private predicate convIdentityMultiple01(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
|
||||
IdentityConvertibleConstructedType toType
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType fromType,
|
||||
IdentityConvertibleGenericType toType
|
||||
) {
|
||||
exists(
|
||||
Type fromTypeArgument0, Type toTypeArgument0, Type fromTypeArgument1, Type toTypeArgument1
|
||||
@@ -270,7 +284,7 @@ private module Identity {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentityMultiple2Aux(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType toType, int i,
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType toType, int i,
|
||||
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
|
||||
@@ -279,8 +293,8 @@ private module Identity {
|
||||
}
|
||||
|
||||
private predicate convIdentityMultiple2(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
|
||||
IdentityConvertibleConstructedType toType, int i
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType fromType,
|
||||
IdentityConvertibleGenericType toType, int i
|
||||
) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convIdentityMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument)
|
||||
@@ -295,8 +309,8 @@ private module Identity {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate convIdentityMultiple(
|
||||
UnboundGenericType ugt, IdentityConvertibleConstructedType fromType,
|
||||
IdentityConvertibleConstructedType toType, int i
|
||||
UnboundGenericType ugt, IdentityConvertibleGenericType fromType,
|
||||
IdentityConvertibleGenericType toType, int i
|
||||
) {
|
||||
convIdentityMultiple01(ugt, fromType, toType) and i = 1
|
||||
or
|
||||
@@ -304,8 +318,8 @@ private module Identity {
|
||||
convIdentityMultiple2(ugt, fromType, toType, i)
|
||||
}
|
||||
|
||||
private predicate convIdentityStrictConstructedType(
|
||||
IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType
|
||||
private predicate convIdentityStrictGenericType(
|
||||
IdentityConvertibleGenericType fromType, IdentityConvertibleGenericType toType
|
||||
) {
|
||||
// Semantically equivalent with
|
||||
// ```
|
||||
@@ -730,7 +744,7 @@ predicate convConversionOperator(Type fromType, Type toType) {
|
||||
}
|
||||
|
||||
/** 13.1.3.2: Variance conversion. */
|
||||
private predicate convVariance(ConstructedType fromType, ConstructedType toType) {
|
||||
private predicate convVariance(GenericType fromType, GenericType toType) {
|
||||
// Semantically equivalent with
|
||||
// ```
|
||||
// ugt = fromType.getUnboundGeneric()
|
||||
@@ -758,34 +772,14 @@ private predicate convVariance(ConstructedType fromType, ConstructedType toType)
|
||||
}
|
||||
|
||||
private module Variance {
|
||||
/**
|
||||
* Holds if constructed type `ct` is potentially variance convertible to
|
||||
* or from another constructed type, as a result of the `i`th type
|
||||
* argument being potentially convertible.
|
||||
*/
|
||||
private predicate isVarianceConvertible(ConstructedType ct, int i) {
|
||||
exists(TypeParameter tp, Type t |
|
||||
tp = ct.getUnboundGeneric().getTypeParameter(i) and
|
||||
t = ct.getTypeArgument(i)
|
||||
|
|
||||
// Anything that is not a type parameter is potentially convertible
|
||||
// to/from another type; if the `i`th type parameter is invariant,
|
||||
// `t` must be strictly identity convertible
|
||||
not t instanceof TypeParameter and
|
||||
(tp.isIn() or tp.isOut() or Identity::convIdentityStrict(t, _))
|
||||
or
|
||||
exists(TypeParameter s | s = t |
|
||||
// A type parameter with implicit reference conversion
|
||||
exists(convTypeParameterBase(s)) and s.isRefType() and tp.isOut()
|
||||
private class VarianceConvertibleGenericType extends GenericType {
|
||||
VarianceConvertibleGenericType() {
|
||||
exists(TypeParameter tp | tp = this.getUnboundGeneric().getATypeParameter() |
|
||||
tp.isIn()
|
||||
or
|
||||
// A type parameter convertible from another type parameter
|
||||
exists(TypeParameter u | s = convTypeParameterBase(u) and u.isRefType() and tp.isIn())
|
||||
tp.isOut()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private class VarianceConvertibleConstructedType extends ConstructedType {
|
||||
VarianceConvertibleConstructedType() { isVarianceConvertible(this, _) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -794,8 +788,8 @@ private module Variance {
|
||||
*/
|
||||
private int getTypeArgumentCount(UnboundGenericType ugt, int i) {
|
||||
result = strictcount(Type arg |
|
||||
exists(VarianceConvertibleConstructedType ct | ct.getUnboundGeneric() = ugt |
|
||||
arg = ct.getTypeArgument(i)
|
||||
exists(VarianceConvertibleGenericType gt | gt.getUnboundGeneric() = ugt |
|
||||
arg = gt.getTypeArgument(i)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -806,7 +800,7 @@ private module Variance {
|
||||
|
||||
/** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */
|
||||
private Type getTypeArgumentRanked(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType t, int i, TypeParameter tp
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType t, int i, TypeParameter tp
|
||||
) {
|
||||
result = getTypeArgument(ugt, t, rnk(ugt, i), tp)
|
||||
}
|
||||
@@ -889,8 +883,8 @@ private module Variance {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceSingle0(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType toType,
|
||||
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType toType, TypeArgument fromTypeArgument,
|
||||
TypeArgument toTypeArgument
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, toType, 0, _) and
|
||||
@@ -902,8 +896,8 @@ private module Variance {
|
||||
* convertible, and the number of type arguments is 1.
|
||||
*/
|
||||
predicate convVarianceSingle(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
|
||||
VarianceConvertibleConstructedType toType
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType fromType,
|
||||
VarianceConvertibleGenericType toType
|
||||
) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convVarianceSingle0(ugt, toType, fromTypeArgument, toTypeArgument)
|
||||
@@ -914,8 +908,8 @@ private module Variance {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceMultiple01Aux0(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType toType,
|
||||
TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType toType, TypeArgument fromTypeArgument0,
|
||||
TypeArgument toTypeArgument0, TypeArgument toTypeArgument1
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and
|
||||
toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0, _) and
|
||||
@@ -924,8 +918,8 @@ private module Variance {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceMultiple01Aux1(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
|
||||
TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType fromType, TypeArgument fromTypeArgument0,
|
||||
TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and
|
||||
fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0, _) and
|
||||
@@ -937,8 +931,8 @@ private module Variance {
|
||||
* are variance convertible.
|
||||
*/
|
||||
private predicate convVarianceMultiple01(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
|
||||
VarianceConvertibleConstructedType toType
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType fromType,
|
||||
VarianceConvertibleGenericType toType
|
||||
) {
|
||||
exists(
|
||||
TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument fromTypeArgument1,
|
||||
@@ -953,7 +947,7 @@ private module Variance {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceMultiple2Aux(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType toType, int i,
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType toType, int i,
|
||||
TypeArgument fromTypeArgument, TypeArgument toTypeArgument
|
||||
) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
|
||||
@@ -962,8 +956,8 @@ private module Variance {
|
||||
}
|
||||
|
||||
private predicate convVarianceMultiple2(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
|
||||
VarianceConvertibleConstructedType toType, int i
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType fromType,
|
||||
VarianceConvertibleGenericType toType, int i
|
||||
) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convVarianceMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument)
|
||||
@@ -978,8 +972,8 @@ private module Variance {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate convVarianceMultiple(
|
||||
UnboundGenericType ugt, VarianceConvertibleConstructedType fromType,
|
||||
VarianceConvertibleConstructedType toType, int i
|
||||
UnboundGenericType ugt, VarianceConvertibleGenericType fromType,
|
||||
VarianceConvertibleGenericType toType, int i
|
||||
) {
|
||||
convVarianceMultiple01(ugt, fromType, toType) and i = 1
|
||||
or
|
||||
|
||||
@@ -74,8 +74,10 @@
|
||||
| I3<C2,C1> | dynamic |
|
||||
| I4<,> | Object |
|
||||
| I4<,> | dynamic |
|
||||
| I4<C1,T4> | I4<,> |
|
||||
| I4<C1,T4> | Object |
|
||||
| I4<C1,T4> | dynamic |
|
||||
| I4<C1,T6> | I4<T5,T6> |
|
||||
| I4<C1,T6> | Object |
|
||||
| I4<C1,T6> | dynamic |
|
||||
| I4<T5,T6> | Object |
|
||||
|
||||
Reference in New Issue
Block a user