mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #2095 from hvitved/csharp/type-unification
C#: Type unification library
This commit is contained in:
@@ -47,5 +47,6 @@ The following changes in version 1.23 affect C# analysis in all applications.
|
||||
`TaintTracking::localExprTaint` predicate to make it easy to use the most
|
||||
common case of local data flow and taint: from one `Expr` to another.
|
||||
* Data is now tracked through null-coalescing expressions (`??`).
|
||||
* A new library `semmle.code.csharp.Unification` has been added. This library exposes two predicates `unifiable` and `subsumes` for calculating type unification and type subsumption, respectively.
|
||||
|
||||
## Changes to autobuilder
|
||||
|
||||
@@ -79,4 +79,21 @@ module Stages {
|
||||
forceCachingInSameStageRev()
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
module UnificationStage {
|
||||
private import semmle.code.csharp.Unification
|
||||
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
private predicate forceCachingInSameStageRev() {
|
||||
exists(CompoundTypeKind k)
|
||||
or
|
||||
exists(Unification::UnconstrainedTypeParameter utp)
|
||||
or
|
||||
forceCachingInSameStageRev()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,29 +15,48 @@ import Type
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.collections.Generic
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if there exists an implicit conversion from `fromType` to `toType`.
|
||||
*
|
||||
* 6.1: Implicit type conversions.
|
||||
*
|
||||
* The following conversions are classified as implicit conversions:
|
||||
*
|
||||
* - Identity conversions
|
||||
* - Implicit numeric conversions
|
||||
* - Implicit nullable conversions
|
||||
* - Implicit reference conversions
|
||||
* - Boxing conversions
|
||||
* - User-defined implicit conversions
|
||||
*/
|
||||
cached
|
||||
predicate implicitConversion(Type fromType, Type toType) {
|
||||
implicitConversionNonNull(fromType, toType)
|
||||
or
|
||||
defaultNullConversion(fromType, toType)
|
||||
private module Cached {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if there exists an implicit conversion from `fromType` to `toType`.
|
||||
*
|
||||
* 6.1: Implicit type conversions.
|
||||
*
|
||||
* The following conversions are classified as implicit conversions:
|
||||
*
|
||||
* - Identity conversions
|
||||
* - Implicit numeric conversions
|
||||
* - Implicit nullable conversions
|
||||
* - Implicit reference conversions
|
||||
* - Boxing conversions
|
||||
* - User-defined implicit conversions
|
||||
*/
|
||||
cached
|
||||
predicate implicitConversion(Type fromType, Type toType) {
|
||||
implicitConversionNonNull(fromType, toType)
|
||||
or
|
||||
defaultNullConversion(fromType, toType)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if there is a constant expression conversion from `fromType` to `toType`.
|
||||
*
|
||||
* 6.1.9: Implicit constant expression conversions.
|
||||
*/
|
||||
cached
|
||||
predicate convConstantExpr(SignedIntegralConstantExpr e, SimpleType toType) {
|
||||
convConstantIntExpr(e, toType)
|
||||
or
|
||||
convConstantLongExpr(e) and toType instanceof ULongType
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
private predicate implicitConversionNonNull(Type fromType, Type toType) {
|
||||
convIdentity(fromType, toType)
|
||||
or
|
||||
@@ -477,7 +496,7 @@ predicate convNullableType(ValueOrRefType fromType, NullableType toType) {
|
||||
// This is a deliberate, small Cartesian product, so we have manually lifted it to force the
|
||||
// evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
|
||||
pragma[noinline]
|
||||
private predicate defaultNullConversion(Type fromType, Type toType) {
|
||||
predicate defaultNullConversion(Type fromType, Type toType) {
|
||||
fromType instanceof NullType and convNullType(toType)
|
||||
}
|
||||
|
||||
@@ -612,19 +631,6 @@ private predicate convBoxingValueType(ValueType fromType, Type toType) {
|
||||
toType = fromType.getABaseInterface+()
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if there is a constant expression conversion from `fromType` to `toType`.
|
||||
*
|
||||
* 6.1.9: Implicit constant expression conversions.
|
||||
*/
|
||||
predicate convConstantExpr(SignedIntegralConstantExpr e, SimpleType toType) {
|
||||
convConstantIntExpr(e, toType)
|
||||
or
|
||||
convConstantLongExpr(e) and toType instanceof ULongType
|
||||
}
|
||||
|
||||
private class SignedIntegralConstantExpr extends Expr {
|
||||
SignedIntegralConstantExpr() {
|
||||
this.getType() instanceof SignedIntegralType and
|
||||
|
||||
@@ -236,63 +236,13 @@ private Type getArgumentOrReturnType(Method m, int i) {
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides an implementation of Global Value Numbering for types
|
||||
* (see https://en.wikipedia.org/wiki/Global_value_numbering), where
|
||||
* types are considered equal modulo identity conversions and method
|
||||
* type parameters (at the same index).
|
||||
*/
|
||||
module Gvn {
|
||||
private newtype TCompoundTypeKind =
|
||||
TPointerTypeKind() or
|
||||
TNullableTypeKind() or
|
||||
TArrayTypeKind(int dim, int rnk) {
|
||||
exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank())
|
||||
} or
|
||||
TConstructedType(UnboundGenericType ugt)
|
||||
|
||||
/** A type kind for a compound type. */
|
||||
class CompoundTypeKind extends TCompoundTypeKind {
|
||||
int getNumberOfTypeParameters() {
|
||||
this = TPointerTypeKind() and result = 1
|
||||
or
|
||||
this = TNullableTypeKind() and result = 1
|
||||
or
|
||||
this = TArrayTypeKind(_, _) and result = 1
|
||||
or
|
||||
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
|
||||
result = ugt.getNumberOfTypeParameters()
|
||||
)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
this = TPointerTypeKind() and result = "*"
|
||||
or
|
||||
this = TNullableTypeKind() and result = "?"
|
||||
or
|
||||
exists(int dim, int rnk | this = TArrayTypeKind(dim, rnk) |
|
||||
result = "[" + dim + ", " + rnk + "]"
|
||||
)
|
||||
or
|
||||
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
|
||||
result = ugt.getNameWithoutBrackets()
|
||||
)
|
||||
}
|
||||
|
||||
Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** Gets the type kind for type `t`, if any. */
|
||||
CompoundTypeKind getTypeKind(Type t) {
|
||||
result = TPointerTypeKind() and t instanceof PointerType
|
||||
or
|
||||
result = TNullableTypeKind() and t instanceof NullableType
|
||||
or
|
||||
t = any(ArrayType at | result = TArrayTypeKind(at.getDimension(), at.getRank()))
|
||||
or
|
||||
result = TConstructedType(t.(ConstructedType).getUnboundGeneric())
|
||||
}
|
||||
private module Gvn {
|
||||
private import semmle.code.csharp.Unification
|
||||
|
||||
private class MethodTypeParameter extends TypeParameter {
|
||||
MethodTypeParameter() { this = any(UnboundGenericMethod ugm).getATypeParameter() }
|
||||
@@ -310,38 +260,47 @@ module Gvn {
|
||||
private newtype TGvnType =
|
||||
TLeafGvnType(int i) { id(_, i) } or
|
||||
TMethodTypeParameterGvnType(int i) { i = any(MethodTypeParameter p).getIndex() } or
|
||||
TConstructedGvnType(TConstructedGvnType0 t)
|
||||
TConstructedGvnType(ConstructedGvnTypeList l)
|
||||
|
||||
private newtype TConstructedGvnType0 =
|
||||
private newtype TConstructedGvnTypeList =
|
||||
TConstructedGvnTypeNil(CompoundTypeKind k) or
|
||||
TConstructedGvnTypeCons(TGvnType head, TConstructedGvnType0 tail) {
|
||||
gvnConstructedCons(_, _, head, tail)
|
||||
TConstructedGvnTypeCons(GvnType head, ConstructedGvnTypeList tail) {
|
||||
gvnConstructedCons(_, _, _, head, tail)
|
||||
}
|
||||
|
||||
private TConstructedGvnType0 gvnConstructed(Type t, int i) {
|
||||
result = TConstructedGvnTypeNil(getTypeKind(t)) and i = -1
|
||||
private ConstructedGvnTypeList gvnConstructed(Type t, CompoundTypeKind k, int i) {
|
||||
result = TConstructedGvnTypeNil(k) and
|
||||
i = -1 and
|
||||
k = getTypeKind(t)
|
||||
or
|
||||
exists(TGvnType head, TConstructedGvnType0 tail | gvnConstructedCons(t, i, head, tail) |
|
||||
exists(GvnType head, ConstructedGvnTypeList tail | gvnConstructedCons(t, k, i, head, tail) |
|
||||
result = TConstructedGvnTypeCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TGvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) }
|
||||
private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate gvnConstructedCons(Type t, int i, TGvnType head, TConstructedGvnType0 tail) {
|
||||
tail = gvnConstructed(t, i - 1) and
|
||||
private predicate gvnConstructedCons(
|
||||
Type t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail
|
||||
) {
|
||||
tail = gvnConstructed(t, k, i - 1) and
|
||||
head = gvnTypeChild(t, i)
|
||||
}
|
||||
|
||||
/** Gets the global value number for a given type. */
|
||||
pragma[nomagic]
|
||||
GvnType getGlobalValueNumber(Type t) {
|
||||
result = TLeafGvnType(any(int i | id(t, i)))
|
||||
or
|
||||
result = TMethodTypeParameterGvnType(t.(MethodTypeParameter).getIndex())
|
||||
or
|
||||
result = TConstructedGvnType(gvnConstructed(t, getTypeKind(t).getNumberOfTypeParameters() - 1))
|
||||
exists(ConstructedGvnTypeList l, CompoundTypeKind k, int i |
|
||||
l = gvnConstructed(t, k, i) and
|
||||
i = k.getNumberOfTypeParameters() - 1 and
|
||||
result = TConstructedGvnType(l)
|
||||
)
|
||||
}
|
||||
|
||||
/** A global value number for a type. */
|
||||
@@ -351,40 +310,42 @@ module Gvn {
|
||||
or
|
||||
exists(int i | this = TMethodTypeParameterGvnType(i) | result = "M!" + i)
|
||||
or
|
||||
exists(GvnConstructedType t | this = TConstructedGvnType(t) | result = t.toString())
|
||||
exists(ConstructedGvnTypeList l | this = TConstructedGvnType(l) | result = l.toString())
|
||||
}
|
||||
|
||||
Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** A global value number for a constructed type. */
|
||||
class GvnConstructedType extends TConstructedGvnType0 {
|
||||
private CompoundTypeKind getKind() {
|
||||
this = TConstructedGvnTypeNil(result)
|
||||
private class ConstructedGvnTypeList extends TConstructedGvnTypeList {
|
||||
private int length() {
|
||||
this = TConstructedGvnTypeNil(_) and result = -1
|
||||
or
|
||||
exists(GvnConstructedType tail | this = TConstructedGvnTypeCons(_, tail) |
|
||||
result = tail.getKind()
|
||||
exists(ConstructedGvnTypeList tail | this = TConstructedGvnTypeCons(_, tail) |
|
||||
result = tail.length() + 1
|
||||
)
|
||||
}
|
||||
|
||||
private GvnType getArg(int i) {
|
||||
this = TConstructedGvnTypeCons(result, TConstructedGvnTypeNil(_)) and
|
||||
i = 0
|
||||
or
|
||||
exists(GvnConstructedType tail | this = TConstructedGvnTypeCons(result, tail) |
|
||||
exists(tail.getArg(i - 1))
|
||||
exists(GvnType head, ConstructedGvnTypeList tail |
|
||||
this = TConstructedGvnTypeCons(head, tail)
|
||||
|
|
||||
result = head and
|
||||
i = this.length()
|
||||
or
|
||||
result = tail.getArg(i)
|
||||
)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
string toString() {
|
||||
exists(CompoundTypeKind k | k = this.getKind() |
|
||||
result = k + "<" +
|
||||
concat(int i |
|
||||
i in [0 .. k.getNumberOfTypeParameters() - 1]
|
||||
|
|
||||
this.getArg(i).toString(), ", "
|
||||
) + ">"
|
||||
exists(CompoundTypeKind k, string args |
|
||||
this = gvnConstructed(_, k, _) and
|
||||
args = concat(int i |
|
||||
i in [0 .. k.getNumberOfTypeParameters() - 1]
|
||||
|
|
||||
this.getArg(i).toString(), ", " order by i
|
||||
) and
|
||||
result = k.toString(args)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -941,6 +941,8 @@ class TupleType extends ValueType, @tuple_type {
|
||||
}
|
||||
|
||||
override string getLabel() { result = getUnderlyingType().getLabel() }
|
||||
|
||||
override Type getChild(int i) { result = this.getUnderlyingType().getChild(i) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
629
csharp/ql/src/semmle/code/csharp/Unification.qll
Normal file
629
csharp/ql/src/semmle/code/csharp/Unification.qll
Normal file
@@ -0,0 +1,629 @@
|
||||
import csharp
|
||||
private import Conversion
|
||||
private import Caching
|
||||
|
||||
pragma[noinline]
|
||||
private Type getAProperSubType(Type t) {
|
||||
not result instanceof DynamicType and
|
||||
not result instanceof NullType and
|
||||
result.isImplicitlyConvertibleTo(t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an implementation of Global Value Numbering for types (see
|
||||
* https://en.wikipedia.org/wiki/Global_value_numbering), where types are considered
|
||||
* equal modulo identity conversions and type parameters.
|
||||
*/
|
||||
private module Gvn {
|
||||
private class LeafType extends Type {
|
||||
LeafType() {
|
||||
not exists(this.getAChild()) and
|
||||
not this instanceof TypeParameter
|
||||
}
|
||||
}
|
||||
|
||||
/** A type kind for a compound type. */
|
||||
class CompoundTypeKindImpl extends TCompoundTypeKind {
|
||||
/** Gets the number of type parameters for this kind. */
|
||||
int getNumberOfTypeParameters() {
|
||||
this = TPointerTypeKind() and result = 1
|
||||
or
|
||||
this = TNullableTypeKind() and result = 1
|
||||
or
|
||||
this = TArrayTypeKind(_, _) and result = 1
|
||||
or
|
||||
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
|
||||
result = ugt.getNumberOfTypeParameters()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this kind when applied to arguments `args`. */
|
||||
bindingset[args]
|
||||
string toString(string args) {
|
||||
this = TPointerTypeKind() and result = args + "*"
|
||||
or
|
||||
this = TNullableTypeKind() and result = args + "?"
|
||||
or
|
||||
exists(int dim, int rnk | this = TArrayTypeKind(dim, rnk) |
|
||||
result = args + "[" + dim + ", " + rnk + "]"
|
||||
)
|
||||
or
|
||||
exists(UnboundGenericType ugt | this = TConstructedType(ugt) |
|
||||
result = ugt.getNameWithoutBrackets() + "<" + args + ">"
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this kind. */
|
||||
string toString() { result = toString("") }
|
||||
|
||||
/** Gets the location of this kind. */
|
||||
Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** Gets the type kind for type `t`, if any. */
|
||||
CompoundTypeKind getTypeKindImpl(Type t) {
|
||||
result = TPointerTypeKind() and t instanceof PointerType
|
||||
or
|
||||
result = TNullableTypeKind() and t instanceof NullableType
|
||||
or
|
||||
t = any(ArrayType at | result = TArrayTypeKind(at.getDimension(), at.getRank()))
|
||||
or
|
||||
result = TConstructedType(t.(ConstructedType).getUnboundGeneric())
|
||||
or
|
||||
result = TConstructedType(t.(TupleType).getUnderlyingType().getUnboundGeneric())
|
||||
or
|
||||
result = TConstructedType(t)
|
||||
}
|
||||
|
||||
/**
|
||||
* A global value number for a type. Two types have the same GVN when they
|
||||
* are structurally equal modulo type parameters and identity conversions.
|
||||
* For example, `Func<T, int>` and `Func<S, int>` have the same GVN, but
|
||||
* `Func<T, int>` and `Func<string, int>` do not.
|
||||
*/
|
||||
class GvnType extends TGvnType {
|
||||
/** Gets the compound type kind of this GVN, if any. */
|
||||
CompoundTypeKind getKind() { none() }
|
||||
|
||||
/** Gets a textual representation of this GVN. */
|
||||
string toString() {
|
||||
exists(int i | this = TLeafGvnType(i) | result = i.toString())
|
||||
or
|
||||
this instanceof TTypeParameterGvnType and
|
||||
result = "<type parameter>"
|
||||
or
|
||||
exists(ConstructedGvnTypeList l | this = TConstructedGvnType(l) | result = l.toString())
|
||||
}
|
||||
|
||||
/** Gets the location of this GVN. */
|
||||
Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
class ConstructedGvnType extends GvnType, TConstructedGvnType {
|
||||
private ConstructedGvnTypeList l;
|
||||
|
||||
ConstructedGvnType() { this = TConstructedGvnType(l) }
|
||||
|
||||
override CompoundTypeKind getKind() { result = l.getKind() }
|
||||
}
|
||||
|
||||
private ConstructedGvnTypeList gvnConstructed(Type t, CompoundTypeKind k, int i) {
|
||||
result = TConstructedGvnTypeNil(k) and
|
||||
i = -1 and
|
||||
k = getTypeKind(t)
|
||||
or
|
||||
exists(GvnType head, ConstructedGvnTypeList tail | gvnConstructedCons(t, k, i, head, tail) |
|
||||
result = TConstructedGvnTypeCons(head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate gvnConstructedCons(
|
||||
Type t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail
|
||||
) {
|
||||
tail = gvnConstructed(t, k, i - 1) and
|
||||
head = gvnTypeChild(t, i)
|
||||
}
|
||||
|
||||
private class ConstructedGvnTypeList extends TConstructedGvnTypeList {
|
||||
CompoundTypeKind getKind() { this = gvnConstructed(_, result, _) }
|
||||
|
||||
private int length() {
|
||||
this = TConstructedGvnTypeNil(_) and result = -1
|
||||
or
|
||||
exists(ConstructedGvnTypeList tail | this = TConstructedGvnTypeCons(_, tail) |
|
||||
result = tail.length() + 1
|
||||
)
|
||||
}
|
||||
|
||||
GvnType getArg(int i) {
|
||||
exists(GvnType head, ConstructedGvnTypeList tail |
|
||||
this = TConstructedGvnTypeCons(head, tail)
|
||||
|
|
||||
result = head and
|
||||
i = this.length()
|
||||
or
|
||||
result = tail.getArg(i)
|
||||
)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
string toString() {
|
||||
exists(CompoundTypeKind k, string args |
|
||||
k = this.getKind() and
|
||||
args = concat(int i |
|
||||
i in [0 .. k.getNumberOfTypeParameters() - 1]
|
||||
|
|
||||
this.getArg(i).toString(), ", " order by i
|
||||
) and
|
||||
result = k.toString(args)
|
||||
)
|
||||
}
|
||||
|
||||
Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** A GVN type that is an argument in a constructed type. */
|
||||
private class GvnTypeArgument extends GvnType {
|
||||
GvnTypeArgument() { this = any(ConstructedGvnTypeList l).getArg(_) }
|
||||
}
|
||||
|
||||
/** Gets the 'i'th type argument of GVN type `t`, which is of kind `k`. */
|
||||
private GvnTypeArgument getTypeArgument(CompoundTypeKind k, ConstructedGvnType t, int i) {
|
||||
exists(ConstructedGvnTypeList l | t = TConstructedGvnType(l) |
|
||||
result = l.getArg(i) and
|
||||
k = l.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private GvnTypeArgument getNonTypeParameterTypeArgument(
|
||||
CompoundTypeKind k, ConstructedGvnType t, int i
|
||||
) {
|
||||
result = getTypeArgument(k, t, i) and
|
||||
result != TTypeParameterGvnType()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate typeArgumentIsTypeParameter(CompoundTypeKind k, ConstructedGvnType t, int i) {
|
||||
getTypeArgument(k, t, i) = TTypeParameterGvnType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Hold if (non-type-parameters) `arg1` and `arg2` are unifiable, and both are
|
||||
* the `i`th type argument of a compound type of kind `k`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate unifiableNonTypeParameterTypeArguments(
|
||||
CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2, int i
|
||||
) {
|
||||
exists(int j |
|
||||
arg1 = getNonTypeParameterTypeArgument(k, _, i) and
|
||||
arg2 = getNonTypeParameterTypeArgument(k, _, j) and
|
||||
i <= j and
|
||||
j <= i
|
||||
|
|
||||
arg1 = arg2
|
||||
or
|
||||
unifiable(arg1, arg2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hold if `arg1` and `arg2` are unifiable, and both are the `i`th type argument
|
||||
* of a compound type of kind `k`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate unifiableTypeArguments(
|
||||
CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2, int i
|
||||
) {
|
||||
unifiableNonTypeParameterTypeArguments(k, arg1, arg2, i)
|
||||
or
|
||||
exists(int j |
|
||||
arg1 = TTypeParameterGvnType() and
|
||||
typeArgumentIsTypeParameter(k, _, i) and
|
||||
arg2 = getTypeArgument(k, _, j) and
|
||||
i <= j and
|
||||
j <= i
|
||||
)
|
||||
or
|
||||
exists(int j |
|
||||
arg1 = getTypeArgument(k, _, i) and
|
||||
typeArgumentIsTypeParameter(k, _, j) and
|
||||
arg2 = TTypeParameterGvnType() and
|
||||
i <= j and
|
||||
j <= i
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate unifiableSingle0(
|
||||
CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg1, GvnTypeArgument arg2
|
||||
) {
|
||||
unifiableTypeArguments(k, arg1, arg2, 0) and
|
||||
arg2 = getTypeArgument(k, t2, 0) and
|
||||
k.getNumberOfTypeParameters() = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type arguments of types `t1` and `t2` are unifiable, `t1`
|
||||
* and `t2` are of the same kind, and the number of type arguments is 1.
|
||||
*/
|
||||
private predicate unifiableSingle(ConstructedGvnType t1, ConstructedGvnType t2) {
|
||||
exists(CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2 |
|
||||
unifiableSingle0(k, t2, arg1, arg2) and
|
||||
arg1 = getTypeArgument(k, t1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate unifiableMultiple01Aux0(
|
||||
CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg10, GvnTypeArgument arg21
|
||||
) {
|
||||
exists(GvnTypeArgument arg20 |
|
||||
unifiableTypeArguments(k, arg10, arg20, 0) and
|
||||
arg20 = getTypeArgument(k, t2, 0) and
|
||||
arg21 = getTypeArgument(k, t2, 1)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate unifiableMultiple01Aux1(
|
||||
CompoundTypeKind k, ConstructedGvnType t1, GvnTypeArgument arg10, GvnTypeArgument arg21
|
||||
) {
|
||||
exists(GvnTypeArgument arg11 |
|
||||
unifiableTypeArguments(k, arg11, arg21, 1) and
|
||||
arg10 = getTypeArgument(k, t1, 0) and
|
||||
arg11 = getTypeArgument(k, t1, 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the first two type arguments of types `t1` and `t2` are unifiable,
|
||||
* and both `t1` and `t2` are of kind `k`.
|
||||
*/
|
||||
private predicate unifiableMultiple01(
|
||||
CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2
|
||||
) {
|
||||
exists(GvnTypeArgument arg10, GvnTypeArgument arg21 |
|
||||
unifiableMultiple01Aux0(k, t2, arg10, arg21) and
|
||||
unifiableMultiple01Aux1(k, t1, arg10, arg21)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate unifiableMultiple2Aux(
|
||||
CompoundTypeKind k, ConstructedGvnType t2, int i, GvnTypeArgument arg1, GvnTypeArgument arg2
|
||||
) {
|
||||
unifiableTypeArguments(k, arg1, arg2, i) and
|
||||
arg2 = getTypeArgument(k, t2, i) and
|
||||
i >= 2
|
||||
}
|
||||
|
||||
private predicate unifiableMultiple2(
|
||||
CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2, int i
|
||||
) {
|
||||
exists(GvnTypeArgument arg1, GvnTypeArgument arg2 |
|
||||
unifiableMultiple2Aux(k, t2, i, arg1, arg2) and
|
||||
arg1 = getTypeArgument(k, t1, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the arguments 0 through `i` (with `i >= 1`) of types
|
||||
* `t1` and `t2` are unifiable, and both `t1` and `t2` are of kind `k`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate unifiableMultiple(
|
||||
CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2, int i
|
||||
) {
|
||||
unifiableMultiple01(k, t1, t2) and i = 1
|
||||
or
|
||||
unifiableMultiple(k, t1, t2, i - 1) and
|
||||
unifiableMultiple2(k, t1, t2, i)
|
||||
}
|
||||
|
||||
private newtype TTypePath =
|
||||
TTypePathNil() or
|
||||
TTypePathCons(int head, TTypePath tail) { exists(getTypeAtCons(_, head, tail)) }
|
||||
|
||||
/**
|
||||
* Gets the GVN inside GVN `t`, by following the path `path`, if any.
|
||||
*/
|
||||
private GvnType getTypeAt(GvnType t, TTypePath path) {
|
||||
path = TTypePathNil() and
|
||||
result = t
|
||||
or
|
||||
exists(ConstructedGvnTypeList l, int head, TTypePath tail |
|
||||
t = TConstructedGvnType(l) and
|
||||
path = TTypePathCons(head, tail) and
|
||||
result = getTypeAtCons(l, head, tail)
|
||||
)
|
||||
}
|
||||
|
||||
private GvnType getTypeAtCons(ConstructedGvnTypeList l, int head, TTypePath tail) {
|
||||
result = getTypeAt(l.getArg(head), tail)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the leaf GVN inside GVN `t`, by following the path `path`, if any.
|
||||
*/
|
||||
private GvnType getLeafTypeAt(GvnType t, TTypePath path) {
|
||||
result = getTypeAt(t, path) and
|
||||
not result instanceof ConstructedGvnType
|
||||
}
|
||||
|
||||
private predicate id(LeafType t, int i) = equivalenceRelation(convIdentity/2)(t, i)
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TCompoundTypeKind =
|
||||
TPointerTypeKind() { Stages::UnificationStage::forceCachingInSameStage() } or
|
||||
TNullableTypeKind() or
|
||||
TArrayTypeKind(int dim, int rnk) {
|
||||
exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank())
|
||||
} or
|
||||
TConstructedType(UnboundGenericType ugt)
|
||||
|
||||
cached
|
||||
newtype TGvnType =
|
||||
TLeafGvnType(int i) { id(_, i) } or
|
||||
TTypeParameterGvnType() or
|
||||
TConstructedGvnType(ConstructedGvnTypeList l)
|
||||
|
||||
cached
|
||||
newtype TConstructedGvnTypeList =
|
||||
TConstructedGvnTypeNil(CompoundTypeKind k) or
|
||||
TConstructedGvnTypeCons(GvnType head, ConstructedGvnTypeList tail) {
|
||||
gvnConstructedCons(_, _, _, head, tail)
|
||||
}
|
||||
|
||||
/** Gets the GVN for type `t`. */
|
||||
cached
|
||||
GvnType getGlobalValueNumber(Type t) {
|
||||
result = TLeafGvnType(any(int i | id(t, i)))
|
||||
or
|
||||
t instanceof TypeParameter and
|
||||
result = TTypeParameterGvnType()
|
||||
or
|
||||
exists(ConstructedGvnTypeList l, CompoundTypeKind k, int i |
|
||||
l = gvnConstructed(t, k, i) and
|
||||
i = k.getNumberOfTypeParameters() - 1 and
|
||||
result = TConstructedGvnType(l)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if GVNs `t1` and `t2` can be unified. That is, is it possible to
|
||||
* replace all type parameters in `t1` and `t2` with some GVNs (possibly
|
||||
* type parameters themselves) to make the two substituted terms equal.
|
||||
*/
|
||||
cached
|
||||
predicate unifiable(ConstructedGvnType t1, ConstructedGvnType t2) {
|
||||
unifiableSingle(t1, t2)
|
||||
or
|
||||
exists(CompoundTypeKind k | unifiableMultiple(k, t1, t2, k.getNumberOfTypeParameters() - 1))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if GVN `t1` subsumes GVN `t2`. That is, is it possible to replace all
|
||||
* type parameters in `t1` with some GVNs (possibly type parameters themselves)
|
||||
* to make the two substituted terms equal.
|
||||
*/
|
||||
cached
|
||||
predicate subsumes(ConstructedGvnType t1, ConstructedGvnType t2) {
|
||||
unifiable(t1, t2) and // subsumption implies unification
|
||||
forall(TTypePath path, GvnType leaf1 | leaf1 = getLeafTypeAt(t1, path) |
|
||||
exists(GvnType child2 | child2 = getTypeAt(t2, path) |
|
||||
leaf1 = TTypeParameterGvnType()
|
||||
or
|
||||
leaf1 = child2
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
}
|
||||
|
||||
class CompoundTypeKind = Gvn::CompoundTypeKindImpl;
|
||||
|
||||
predicate getTypeKind = Gvn::getTypeKindImpl/1;
|
||||
|
||||
/** Provides definitions related to type unification. */
|
||||
module Unification {
|
||||
/** A type parameter that is compatible with any type. */
|
||||
class UnconstrainedTypeParameter extends TypeParameter {
|
||||
UnconstrainedTypeParameter() { not exists(getATypeConstraint(this)) }
|
||||
}
|
||||
|
||||
/** A type parameter that is constrained. */
|
||||
class ConstrainedTypeParameter extends TypeParameter {
|
||||
int constraintCount;
|
||||
|
||||
ConstrainedTypeParameter() { constraintCount = strictcount(getATypeConstraint(this)) }
|
||||
|
||||
/**
|
||||
* Holds if this type parameter is unifiable with type `t`.
|
||||
*
|
||||
* Note: This predicate is inlined.
|
||||
*/
|
||||
bindingset[t]
|
||||
predicate unifiable(Type t) { none() }
|
||||
|
||||
/**
|
||||
* Holds if this type parameter subsumes type `t`
|
||||
*
|
||||
* Note: This predicate is inlined.
|
||||
*/
|
||||
bindingset[t]
|
||||
predicate subsumes(Type t) { none() }
|
||||
}
|
||||
|
||||
/** A type parameter that has a single constraint. */
|
||||
private class SingleConstraintTypeParameter extends ConstrainedTypeParameter {
|
||||
SingleConstraintTypeParameter() { constraintCount = 1 }
|
||||
|
||||
bindingset[t]
|
||||
override predicate unifiable(Type t) {
|
||||
exists(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
|
||||
ttc = TRefTypeConstraint() and
|
||||
t.isRefType()
|
||||
or
|
||||
ttc = TValueTypeConstraint() and
|
||||
t.isValueType()
|
||||
or
|
||||
typeConstraintUnifiable(ttc, t)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[t]
|
||||
override predicate subsumes(Type t) {
|
||||
exists(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
|
||||
ttc = TRefTypeConstraint() and
|
||||
t.isRefType()
|
||||
or
|
||||
ttc = TValueTypeConstraint() and
|
||||
t.isValueType()
|
||||
or
|
||||
typeConstraintSubsumes(ttc, t)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A type parameter that has multiple constraints. */
|
||||
private class MultiConstraintTypeParameter extends ConstrainedTypeParameter {
|
||||
MultiConstraintTypeParameter() { constraintCount > 1 }
|
||||
|
||||
bindingset[t]
|
||||
override predicate unifiable(Type t) {
|
||||
forex(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
|
||||
ttc = TRefTypeConstraint() and
|
||||
t.isRefType()
|
||||
or
|
||||
ttc = TValueTypeConstraint() and
|
||||
t.isValueType()
|
||||
or
|
||||
typeConstraintUnifiable(ttc, t)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[t]
|
||||
override predicate subsumes(Type t) {
|
||||
forex(TTypeParameterConstraint ttc | ttc = getATypeConstraint(this) |
|
||||
ttc = TRefTypeConstraint() and
|
||||
t.isRefType()
|
||||
or
|
||||
ttc = TValueTypeConstraint() and
|
||||
t.isValueType()
|
||||
or
|
||||
typeConstraintSubsumes(ttc, t)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TTypeParameterConstraint =
|
||||
TRefTypeConstraint() or
|
||||
TValueTypeConstraint() or
|
||||
TTypeConstraint(Type t) {
|
||||
t = any(TypeParameterConstraints tpc).getATypeConstraint() and
|
||||
not t instanceof TypeParameter
|
||||
}
|
||||
|
||||
cached
|
||||
TTypeParameterConstraint getATypeConstraint(TypeParameter tp) {
|
||||
exists(TypeParameterConstraints tpc | tpc = tp.getConstraints() |
|
||||
tpc.hasRefTypeConstraint() and
|
||||
result = TRefTypeConstraint()
|
||||
or
|
||||
tpc.hasNullableRefTypeConstraint() and
|
||||
result = TRefTypeConstraint()
|
||||
or
|
||||
tpc.hasValueTypeConstraint() and
|
||||
result = TValueTypeConstraint()
|
||||
or
|
||||
result = TTypeConstraint(tpc.getATypeConstraint())
|
||||
or
|
||||
result = getATypeConstraint(tpc.getATypeConstraint())
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate typeConstraintUnifiable(TTypeConstraint ttc, Type t) {
|
||||
exists(Type t0 | ttc = TTypeConstraint(t0) | t = getAProperSubType(t0))
|
||||
or
|
||||
exists(Type t0, Type t1 | ttc = TTypeConstraint(t0) and unifiable(t0, t1) |
|
||||
t = getAProperSubType(t1)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate typeConstraintSubsumes(TTypeConstraint ttc, Type t) {
|
||||
exists(Type t0 | ttc = TTypeConstraint(t0) | t = getAProperSubType(t0))
|
||||
or
|
||||
exists(Type t0, Type t1 | ttc = TTypeConstraint(t0) and subsumes(t0, t1) |
|
||||
t = getAProperSubType(t1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private import Cached
|
||||
|
||||
/**
|
||||
* Holds if types `t1` and `t2` are unifiable. That is, is it possible to replace
|
||||
* all type parameters in `t1` and `t2` with some (other) types to make the two
|
||||
* substituted terms equal.
|
||||
*
|
||||
* This predicate covers only the case when `t1` and `t2` are constructed types;
|
||||
* the other three cases are:
|
||||
*
|
||||
* 1. Neither `t1` nor `t2` are type parameters; in this case `t1` and `t2` must
|
||||
* be equal.
|
||||
* 2. `t1` or `t2` is an unconstrained type parameter; in this case `t1` and
|
||||
* `t2` are always unifiable.
|
||||
* 3. `t1` or `t2` is a constrained type parameter; in this case the predicate
|
||||
* `ConstrainedTypeParameter::unifiable()` can be used.
|
||||
*
|
||||
*
|
||||
* For performance reasons, type paramater constraints inside `t1` and `t2` are
|
||||
* *not* taken into account, and there is also no guarantee that the same type
|
||||
* parameter can be substituted with two different terms. For example, in
|
||||
*
|
||||
* ```csharp
|
||||
* class C<T1, T2>
|
||||
* {
|
||||
* void M<T3>(C<T3, T3> c) where T3 : struct { }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* the type `C<T3, T3>` is considered unifiable with both `C<object, object>` and
|
||||
* `C<int, bool>`.
|
||||
*
|
||||
* Note: This predicate is inlined.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate unifiable(Type t1, Type t2) {
|
||||
Gvn::unifiable(Gvn::getGlobalValueNumber(t1), Gvn::getGlobalValueNumber(t2))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if type `t1` subsumes type `t2`. That is, is it possible to replace all
|
||||
* type parameters in `t1` with some (other) types to make the two types equal.
|
||||
*
|
||||
* The same limitations that apply to the predicate `unifiable()` apply to this
|
||||
* predicate as well.
|
||||
*
|
||||
* Note: This predicate is inlined.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate subsumes(Type t1, Type t2) {
|
||||
Gvn::subsumes(Gvn::getGlobalValueNumber(t1), Gvn::getGlobalValueNumber(t2))
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,6 @@
|
||||
|
||||
import csharp
|
||||
private import RuntimeCallable
|
||||
private import OverridableCallable
|
||||
private import semmle.code.csharp.Conversion
|
||||
private import semmle.code.csharp.dataflow.internal.Steps
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.Reflection
|
||||
|
||||
/** A call. */
|
||||
class DispatchCall extends Internal::TDispatchCall {
|
||||
@@ -39,7 +34,12 @@ class DispatchCall extends Internal::TDispatchCall {
|
||||
|
||||
/** Internal implementation details. */
|
||||
private module Internal {
|
||||
private import semmle.code.csharp.Implements
|
||||
private import OverridableCallable
|
||||
private import semmle.code.csharp.Conversion
|
||||
private import semmle.code.csharp.Unification
|
||||
private import semmle.code.csharp.dataflow.internal.Steps
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.Reflection
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -166,7 +166,10 @@ private module Internal {
|
||||
/** A call. */
|
||||
abstract private class DispatchCallImpl extends TDispatchCall {
|
||||
/** Gets a textual representation of this call. */
|
||||
string toString() { none() }
|
||||
string toString() { result = this.getCall().toString() }
|
||||
|
||||
/** Gets the location of this call. */
|
||||
Location getLocation() { result = this.getCall().getLocation() }
|
||||
|
||||
/** Gets the underlying expression of this call. */
|
||||
abstract Expr getCall();
|
||||
@@ -185,56 +188,65 @@ private module Internal {
|
||||
|
||||
/** Gets a dynamic (run-time) target of this call, if any. */
|
||||
abstract RuntimeCallable getADynamicTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the qualifier of this call has type `qualifierType`.
|
||||
* `isExactType` indicates whether the type is exact, that is, whether
|
||||
* the qualifier is guaranteed not to be a subtype of `qualifierType`.
|
||||
*/
|
||||
predicate hasQualifierType(Type qualifierType, boolean isExactType) {
|
||||
exists(Type trackedType | trackedType = getAPossibleType(this.getQualifier(), isExactType) |
|
||||
qualifierType = trackedType and
|
||||
not qualifierType instanceof TypeParameter
|
||||
or
|
||||
qualifierType = trackedType.(TypeParameter).getAnUltimatelySuppliedType()
|
||||
)
|
||||
pragma[noinline]
|
||||
private predicate hasCallable(OverridableCallable source, ValueOrRefType t, OverridableCallable c) {
|
||||
c.getSourceDeclaration() = source and
|
||||
t.hasCallable(c) and
|
||||
hasQualifierTypeOverridden0(t, _) and
|
||||
hasQualifierTypeOverridden1(source, _)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Unification::ConstrainedTypeParameter getAConstrainedTypeParameterQualifierType(
|
||||
DispatchMethodOrAccessorCall call
|
||||
) {
|
||||
result = getAPossibleType(call.getQualifier(), false)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate constrainedTypeParameterQualifierTypeSubsumes(
|
||||
ValueOrRefType t, Unification::ConstrainedTypeParameter tp
|
||||
) {
|
||||
tp = getAConstrainedTypeParameterQualifierType(_) and
|
||||
tp.subsumes(t)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) {
|
||||
exists(Type t0 | t0 = getAPossibleType(call.getQualifier(), false) |
|
||||
t = t0
|
||||
or
|
||||
Unification::subsumes(t0, t)
|
||||
or
|
||||
t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()
|
||||
)
|
||||
or
|
||||
constrainedTypeParameterQualifierTypeSubsumes(t, getAConstrainedTypeParameterQualifierType(call))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasQualifierTypeOverridden1(
|
||||
OverridableCallable c, DispatchMethodOrAccessorCall call
|
||||
) {
|
||||
exists(OverridableCallable target | call.getAStaticTarget() = target |
|
||||
c = target.getSourceDeclaration()
|
||||
or
|
||||
c = target.getAnUltimateImplementor().getSourceDeclaration()
|
||||
)
|
||||
}
|
||||
|
||||
abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl {
|
||||
pragma[nomagic]
|
||||
predicate hasQualifierTypeInherited(SourceDeclarationType t) {
|
||||
t = getAPossibleType(this.getQualifier(), _).getSourceDeclaration()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call
|
||||
* that does not contain type parameters.
|
||||
*/
|
||||
private TypeWithoutTypeParameters getANonExactQualifierTypeWithoutTypeParameters() {
|
||||
exists(Type qualifierType | hasQualifierType(qualifierType, false) |
|
||||
// Qualifier type contains no type parameters: use it
|
||||
result = qualifierType
|
||||
or
|
||||
// Qualifier type is a constructed type where all type arguments are type
|
||||
// parameters: use the unbound generic type
|
||||
exists(ConstructedType ct |
|
||||
ct = qualifierType and
|
||||
forex(Type arg | arg = ct.getATypeArgument() | arg instanceof TypeParameter) and
|
||||
result = ct.getUnboundGeneric()
|
||||
)
|
||||
or
|
||||
// Qualifier type is a constructed type where some (but not all) type arguments
|
||||
// are type parameters: consider all potential instantiations
|
||||
result = qualifierType.(QualifierTypeWithTypeParameters).getAPotentialInstance()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-exact (see `hasQualifierType()`) qualifier type of this call.
|
||||
*/
|
||||
ValueOrRefType getANonExactQualifierType() {
|
||||
exists(TypeWithoutTypeParameters t |
|
||||
t = this.getANonExactQualifierTypeWithoutTypeParameters()
|
||||
|
|
||||
result.(ConstructedType).getUnboundGeneric() = t
|
||||
or
|
||||
not t instanceof UnboundGenericType and
|
||||
result = t
|
||||
)
|
||||
pragma[nomagic]
|
||||
predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) {
|
||||
hasQualifierTypeOverridden0(t, this) and
|
||||
hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,7 +406,7 @@ private module Internal {
|
||||
* The set of viable targets is determined by taking virtual dispatch
|
||||
* into account.
|
||||
*/
|
||||
private class DispatchMethodCall extends DispatchCallImpl, TDispatchMethodCall {
|
||||
private class DispatchMethodCall extends DispatchMethodOrAccessorCall, TDispatchMethodCall {
|
||||
override MethodCall getCall() { this = TDispatchMethodCall(result) }
|
||||
|
||||
override Expr getArgument(int i) {
|
||||
@@ -453,11 +465,14 @@ private module Internal {
|
||||
* `B.M`, and `B.M`, respectively.
|
||||
*/
|
||||
private RuntimeInstanceMethod getViableInherited() {
|
||||
exists(NonConstructedOverridableMethod m, Type qualifierType, SourceDeclarationType t |
|
||||
getAStaticTarget() = m.getAConstructingMethodOrSelf() and
|
||||
hasQualifierType(qualifierType, _) and
|
||||
t = qualifierType.getSourceDeclaration() and
|
||||
exists(NonConstructedOverridableMethod m, SourceDeclarationType t |
|
||||
this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and
|
||||
this.hasQualifierTypeInherited(t)
|
||||
|
|
||||
result = m.getInherited(t)
|
||||
or
|
||||
t instanceof TypeParameter and
|
||||
result = m
|
||||
)
|
||||
}
|
||||
|
||||
@@ -498,8 +513,7 @@ private module Internal {
|
||||
*/
|
||||
private RuntimeInstanceMethod getAViableOverrider() {
|
||||
exists(ValueOrRefType t, NonConstructedOverridableMethod m |
|
||||
t = this.getANonExactQualifierType() and
|
||||
this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and
|
||||
this.hasQualifierTypeOverridden(t, m.getAConstructingMethodOrSelf()) and
|
||||
result = m.getAnOverrider(t)
|
||||
)
|
||||
}
|
||||
@@ -514,7 +528,7 @@ private module Internal {
|
||||
* The set of viable targets is determined by taking virtual dispatch
|
||||
* into account.
|
||||
*/
|
||||
private class DispatchAccessorCall extends DispatchCallImpl, TDispatchAccessorCall {
|
||||
private class DispatchAccessorCall extends DispatchMethodOrAccessorCall, TDispatchAccessorCall {
|
||||
override AccessorCall getCall() { this = TDispatchAccessorCall(result) }
|
||||
|
||||
override Expr getArgument(int i) { result = getCall().getArgument(i) }
|
||||
@@ -587,19 +601,11 @@ private module Internal {
|
||||
private RuntimeAccessor getViableInherited() {
|
||||
exists(OverridableAccessor a, SourceDeclarationType t |
|
||||
this.getAStaticTarget() = a and
|
||||
this.hasQualifierTypeSourceDecl(t) and
|
||||
this.hasQualifierTypeInherited(t) and
|
||||
result = a.getInherited(t)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasQualifierTypeSourceDecl(SourceDeclarationType t) {
|
||||
exists(Type qualifierType |
|
||||
this.hasQualifierType(qualifierType, _) and
|
||||
t = qualifierType.getSourceDeclaration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an accessor that is defined in a subtype of the qualifier type of
|
||||
* this call, and which overrides the static target of this call.
|
||||
@@ -637,110 +643,32 @@ private module Internal {
|
||||
* respectively.
|
||||
*/
|
||||
private RuntimeAccessor getAViableOverrider() {
|
||||
exists(ValueOrRefType t | t = this.getANonExactQualifierType() |
|
||||
result = this.getAStaticTarget().(OverridableAccessor).getAnOverrider(t)
|
||||
exists(ValueOrRefType t, OverridableAccessor a |
|
||||
this.hasQualifierTypeOverridden(t, a) and
|
||||
result = a.getAnOverrider(t)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An internal helper class for comparing two types modulo type parameters. */
|
||||
abstract private class StructurallyComparedModuloTypeParameters extends Type {
|
||||
/** Gets a candidate for comparison against this type. */
|
||||
abstract Type getACandidate();
|
||||
|
||||
/**
|
||||
* Holds if this type equals the type `t` modulo type parameters.
|
||||
*
|
||||
* Equality modulo type parameters is a weaker form of type unifiability.
|
||||
* That is, if constructed types `s` and `t` are unifiable, then `s` and
|
||||
* `t` are equal modulo type parameters, but the converse does not
|
||||
* necessarily hold. (For example, `C<int, string, T, T[]>` and
|
||||
* `C<T, T, int, string[]>` are equal modulo type parameters, but not
|
||||
* unifiable.)
|
||||
*/
|
||||
predicate equalsModuloTypeParameters(Type t) {
|
||||
t = getACandidate() and
|
||||
sameModuloTypeParameters(this, t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a potential instantiation of this type.
|
||||
*
|
||||
* A potential instantiation is a type without type parameters that
|
||||
* is the result of replacing all type parameters in this type with
|
||||
* non-type parameters. Note: the same type parameter may be replaced
|
||||
* by different types at different positions. For example,
|
||||
* `C<int, string>` is considered a potential instantiation of `C<T, T>`.
|
||||
*/
|
||||
TypeWithoutTypeParameters getAPotentialInstance() { equalsModuloTypeParameters(result) }
|
||||
}
|
||||
|
||||
private Type candidateInternal(Type t) {
|
||||
result = t.(StructurallyComparedModuloTypeParameters).getACandidate()
|
||||
or
|
||||
exists(Type parent, Type uncle, int i |
|
||||
uncle = candidateInternal(parent) and
|
||||
t = parent.getChild(i) and
|
||||
result = uncle.getChild(i)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if types `x` and `y` are equal modulo type parameters. */
|
||||
private predicate sameModuloTypeParameters(Type x, Type y) {
|
||||
y = candidateInternal(x) and
|
||||
(
|
||||
x = y
|
||||
or
|
||||
x instanceof TypeParameter
|
||||
or
|
||||
y instanceof TypeParameter
|
||||
or
|
||||
// All of the children must be structurally equal
|
||||
sameChildrenModuloTypeParameters(x, y, x.getNumberOfChildren() - 1)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Type candidateInternalKind(Type t, Gvn::CompoundTypeKind k) {
|
||||
result = candidateInternal(t) and
|
||||
k = Gvn::getTypeKind(t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i+1` first children of types `x` and `y` are equal
|
||||
* modulo type parameters.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate sameChildrenModuloTypeParameters(Type x, Type y, int i) {
|
||||
i = -1 and
|
||||
y = candidateInternalKind(x, Gvn::getTypeKind(y))
|
||||
or
|
||||
sameChildrenModuloTypeParameters(x, y, i - 1) and
|
||||
sameModuloTypeParameters(x.getChild(i), y.getChild(i))
|
||||
}
|
||||
|
||||
/**
|
||||
* A qualifier type containing type parameters for which at
|
||||
* least one of the type arguments is *not* a type parameter.
|
||||
*/
|
||||
private class QualifierTypeWithTypeParameters extends StructurallyComparedModuloTypeParameters {
|
||||
QualifierTypeWithTypeParameters() {
|
||||
containsTypeParameters() and
|
||||
any(DispatchCallImpl dc).hasQualifierType(this, false) and
|
||||
exists(Type arg | arg = getAChild() | not arg instanceof TypeParameter)
|
||||
}
|
||||
|
||||
override ConstructedType getACandidate() {
|
||||
not result.containsTypeParameters() and
|
||||
this.(ConstructedType).getUnboundGeneric() = result.getUnboundGeneric()
|
||||
}
|
||||
}
|
||||
|
||||
/** A reflection-based call or a call using dynamic types. */
|
||||
abstract private class DispatchReflectionOrDynamicCall extends DispatchCallImpl {
|
||||
/** Gets the name of the callable being called in this call. */
|
||||
abstract string getName();
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasQualifierType(Type qualifierType, boolean isExactType) {
|
||||
exists(Type t | t = getAPossibleType(this.getQualifier(), isExactType) |
|
||||
qualifierType = t and
|
||||
not t instanceof TypeParameter
|
||||
or
|
||||
Unification::subsumes(t, qualifierType)
|
||||
or
|
||||
t.(Unification::ConstrainedTypeParameter).unifiable(qualifierType)
|
||||
or
|
||||
qualifierType = t.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a potential qualifier type of this call.
|
||||
*
|
||||
@@ -779,21 +707,17 @@ private module Internal {
|
||||
this.hasQualifierType(result, true)
|
||||
or
|
||||
// Non-exact qualifier type
|
||||
exists(Type qualifierType | this.hasNonExactQualifierType(qualifierType) |
|
||||
exists(Type qualifierType | this.hasQualifierType(qualifierType, false) |
|
||||
result = getANonExactQualifierSubType(qualifierType)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasNonExactQualifierType(Type qualifierType) {
|
||||
this.hasQualifierType(qualifierType, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the qualifier type is unknown (it is either `object` or
|
||||
* `dynamic`).
|
||||
*/
|
||||
private predicate hasUnknownQualifierType() {
|
||||
exists(Type qualifierType | this.hasNonExactQualifierType(qualifierType) |
|
||||
exists(Type qualifierType | this.hasQualifierType(qualifierType, false) |
|
||||
isUnknownType(qualifierType)
|
||||
)
|
||||
}
|
||||
@@ -952,10 +876,21 @@ private module Internal {
|
||||
private predicate reflectionOrDynamicArgEqualsParamModuloTypeParameters(
|
||||
Type argumentType, Type parameterType
|
||||
) {
|
||||
exists(Type t | reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(argumentType, t) |
|
||||
t
|
||||
.(ReflectionOrDynamicCallArgumentWithTypeParameters)
|
||||
.equalsModuloTypeParameters(parameterType)
|
||||
exists(Type t |
|
||||
reflectionOrDynamicArgumentTypeIsImplicitlyConvertibleTo(argumentType, t) and
|
||||
isReflectionOrDynamicCallArgumentWithTypeParameters(t, parameterType)
|
||||
|
|
||||
parameterType = t
|
||||
or
|
||||
t instanceof Unification::UnconstrainedTypeParameter
|
||||
or
|
||||
parameterType instanceof Unification::UnconstrainedTypeParameter
|
||||
or
|
||||
t.(Unification::ConstrainedTypeParameter).unifiable(parameterType)
|
||||
or
|
||||
parameterType.(Unification::ConstrainedTypeParameter).unifiable(t)
|
||||
or
|
||||
Unification::unifiable(parameterType, t)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -999,21 +934,6 @@ private module Internal {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that is the argument type of a reflection-based call or a call using
|
||||
* dynamic types, where either the type or the relevant parameter type of a
|
||||
* potential run-time target contains type parameters.
|
||||
*/
|
||||
private class ReflectionOrDynamicCallArgumentWithTypeParameters extends StructurallyComparedModuloTypeParameters {
|
||||
ReflectionOrDynamicCallArgumentWithTypeParameters() {
|
||||
isReflectionOrDynamicCallArgumentWithTypeParameters(this, _)
|
||||
}
|
||||
|
||||
override Type getACandidate() {
|
||||
isReflectionOrDynamicCallArgumentWithTypeParameters(this, result)
|
||||
}
|
||||
}
|
||||
|
||||
/** A call using reflection. */
|
||||
private class DispatchReflectionCall extends DispatchReflectionOrDynamicCall,
|
||||
TDispatchReflectionCall {
|
||||
|
||||
@@ -185,28 +185,16 @@ class OverridableCallable extends Callable {
|
||||
|
||||
pragma[noinline]
|
||||
private Callable getAnOverrider0(ValueOrRefType t) {
|
||||
not this.declaredInTypeWithTypeParameters() and
|
||||
(
|
||||
// A (transitive) overrider
|
||||
result = this.getAnOverrider+() and
|
||||
t = result.getDeclaringType()
|
||||
or
|
||||
// An interface implementation
|
||||
result = this.getAnImplementorSubType(t)
|
||||
or
|
||||
// A (transitive) overrider of an interface implementation
|
||||
result = this.getAnOverridingImplementor() and
|
||||
t = result.getDeclaringType()
|
||||
)
|
||||
}
|
||||
|
||||
private Callable getAnOverrider1(ValueOrRefType t) {
|
||||
result = this.getAnOverrider0(t)
|
||||
// A (transitive) overrider
|
||||
result = this.getAnOverrider+() and
|
||||
t = result.getDeclaringType()
|
||||
or
|
||||
exists(ValueOrRefType mid | result = this.getAnOverrider1(mid) |
|
||||
t = mid.getABaseType() and
|
||||
this.isDeclaringSubType(t)
|
||||
)
|
||||
// An interface implementation
|
||||
result = this.getAnImplementorSubType(t)
|
||||
or
|
||||
// A (transitive) overrider of an interface implementation
|
||||
result = this.getAnOverridingImplementor() and
|
||||
t = result.getDeclaringType()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,36 +208,12 @@ class OverridableCallable extends Callable {
|
||||
* contains a callable that overrides this callable, then only if `C2<int>`
|
||||
* is ever constructed will the callable in `C2` be considered valid.
|
||||
*/
|
||||
Callable getAnOverrider(ValueOrRefType t) { result = this.getABoundInstance().getAnOverrider1(t) }
|
||||
|
||||
/**
|
||||
* Gets a bound instance of this callable.
|
||||
*
|
||||
* If this callable is defined in a type that contains type parameters,
|
||||
* returns an instance defined in a constructed type, otherwise the
|
||||
* callable itself.
|
||||
*/
|
||||
private OverridableCallable getABoundInstance() {
|
||||
not declaredInTypeWithTypeParameters() and
|
||||
result = this
|
||||
Callable getAnOverrider(ValueOrRefType t) {
|
||||
result = this.getAnOverrider0(t)
|
||||
or
|
||||
result.getSourceDeclaration() = getSourceDeclarationInTypeWithTypeParameters()
|
||||
}
|
||||
|
||||
// predicate folding to get proper join order
|
||||
private OverridableCallable getSourceDeclarationInTypeWithTypeParameters() {
|
||||
declaredInTypeWithTypeParameters() and
|
||||
result = getSourceDeclaration()
|
||||
}
|
||||
|
||||
private predicate declaredInTypeWithTypeParameters() {
|
||||
exists(ValueOrRefType t | t = getDeclaringType() |
|
||||
t.containsTypeParameters()
|
||||
or
|
||||
// Access to a local callable, `this.M()`, in a generic class
|
||||
// results in a static target where the declaring type is
|
||||
// the unbound generic version
|
||||
t instanceof UnboundGenericType
|
||||
exists(ValueOrRefType mid | result = this.getAnOverrider(mid) |
|
||||
t = mid.getABaseType() and
|
||||
this.isDeclaringSubType(t)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -328,12 +292,7 @@ private int getAccessorKind(Accessor a) {
|
||||
event_accessors(a, -result, _, _, _)
|
||||
}
|
||||
|
||||
/** A type not containing type parameters. */
|
||||
class TypeWithoutTypeParameters extends Type {
|
||||
TypeWithoutTypeParameters() { not containsTypeParameters() }
|
||||
}
|
||||
|
||||
/** A source declared type. */
|
||||
class SourceDeclarationType extends TypeWithoutTypeParameters {
|
||||
SourceDeclarationType() { this = getSourceDeclaration() }
|
||||
class SourceDeclarationType extends Type {
|
||||
SourceDeclarationType() { this = this.getSourceDeclaration() }
|
||||
}
|
||||
|
||||
@@ -41,21 +41,28 @@
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:35:242:37 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:242:40:242:42 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:40:243:42 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:243:71:243:73 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:56:244:58 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:244:64:244:69 | remove_Event |
|
||||
@@ -67,11 +74,18 @@
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:252:56:252:58 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:252:64:252:69 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:257:26:257:30 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:257:26:257:30 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:32:258:34 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:32:258:34 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:37:258:39 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:258:37:258:39 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:40:259:42 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:40:259:42 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:71:259:73 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:259:71:259:73 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:53:260:55 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:53:260:55 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:61:260:66 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:260:61:260:66 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:265:26:265:30 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:266:24:266:24 | M |
|
||||
@@ -91,6 +105,11 @@
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:31:277:33 | get_Prop |
|
||||
@@ -103,6 +122,12 @@
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:277:36:277:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:37:278:39 | get_Item |
|
||||
@@ -115,12 +140,21 @@
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:278:68:278:70 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:52:279:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
@@ -128,11 +162,18 @@
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:279:60:279:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:293:26:293:30 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:293:26:293:30 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:31:294:33 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:31:294:33 | get_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:36:294:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:294:36:294:38 | set_Prop |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:39:295:41 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:39:295:41 | get_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:70:295:72 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:295:70:295:72 | set_Item |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:52:296:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:52:296:54 | add_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:60:296:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:296:60:296:65 | remove_Event |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:313:25:313:25 | M |
|
||||
| ViableCallable.cs:9:17:9:31 | Run | ViableCallable.cs:314:24:314:28 | M2 |
|
||||
@@ -152,17 +193,25 @@
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:241:23:241:27 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:249:29:249:33 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:257:26:257:30 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:257:26:257:30 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:265:26:265:30 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:293:26:293:30 | M |
|
||||
| ViableCallable.cs:232:17:232:19 | Run | ViableCallable.cs:293:26:293:30 | M |
|
||||
| ViableCallable.cs:281:17:281:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:281:17:281:19 | Run | ViableCallable.cs:293:26:293:30 | M |
|
||||
| ViableCallable.cs:281:17:281:19 | Run | ViableCallable.cs:293:26:293:30 | M |
|
||||
| ViableCallable.cs:298:17:298:19 | Run | ViableCallable.cs:276:24:276:28 | M |
|
||||
| ViableCallable.cs:298:17:298:19 | Run | ViableCallable.cs:293:26:293:30 | M |
|
||||
| ViableCallable.cs:348:17:348:19 | Run | ViableCallable.cs:346:10:346:10 | M |
|
||||
@@ -174,6 +223,16 @@
|
||||
| ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:397:36:397:40 | M |
|
||||
| ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:403:53:403:57 | M |
|
||||
| ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:405:42:405:46 | M |
|
||||
| ViableCallable.cs:431:25:431:29 | M2 | ViableCallable.cs:442:17:442:23 | (...) => ... |
|
||||
| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:430:23:430:24 | M1 |
|
||||
| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:431:25:431:29 | M2 |
|
||||
| ViableCallable.cs:431:22:431:26 | M2 | ViableCallable.cs:456:14:456:29 | (...) => ... |
|
||||
| ViableCallable.cs:431:22:431:26 | M2 | ViableCallable.cs:462:14:462:29 | (...) => ... |
|
||||
| ViableCallable.cs:436:10:436:11 | M1 | ViableCallable.cs:430:23:430:24 | M1 |
|
||||
| ViableCallable.cs:436:10:436:11 | M1 | ViableCallable.cs:445:23:445:27 | M2 |
|
||||
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:442:17:442:23 | (...) => ... |
|
||||
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:450:14:450:20 | (...) => ... |
|
||||
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:456:14:456:29 | (...) => ... |
|
||||
| ViableCallable.cs:445:23:445:27 | M2 | ViableCallable.cs:462:14:462:29 | (...) => ... |
|
||||
| ViableCallable.cs:447:10:447:14 | M3 | ViableCallable.cs:445:23:445:27 | M2 |
|
||||
| ViableCallable.cs:453:10:453:14 | M4 | ViableCallable.cs:431:22:431:26 | M2 |
|
||||
| ViableCallable.cs:453:10:453:14 | M4 | ViableCallable.cs:445:23:445:27 | M2 |
|
||||
| ViableCallable.cs:459:10:459:14 | M5 | ViableCallable.cs:431:22:431:26 | M2 |
|
||||
| ViableCallable.cs:459:10:459:14 | M5 | ViableCallable.cs:445:23:445:27 | M2 |
|
||||
|
||||
@@ -66,102 +66,151 @@
|
||||
| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.C2.Method() |
|
||||
| TypeFlow.cs:37:11:37:26 | call to method Method | TypeFlow.C2.Method() |
|
||||
| TypeFlow.cs:40:9:40:18 | call to method Method | TypeFlow.C2.Method() |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C2<>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C2<Boolean>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C2<Decimal>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C2<Int32>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C3.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C4<>.M<T3>(T[], T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C4<Int32>.M<T3>(int[], T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C5.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<,>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<Boolean,Byte>.M<T3>(bool, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<Int32[],Boolean>.M<T3>(int[], T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<String,Boolean>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<String,Decimal>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<String,Int32>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<T1,Boolean>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C6<T1,Byte>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C7<>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:12:9:12:28 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<>.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<Boolean>.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<Decimal>.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C2<Int32>.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C3.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C4<>.set_Prop(T[]) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C4<Int32>.set_Prop(int[]) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C5.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<,>.set_Prop(T1) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<Boolean,Byte>.set_Prop(bool) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<Int32[],Boolean>.set_Prop(int[]) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<String,Boolean>.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<String,Decimal>.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<String,Int32>.set_Prop(string) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<T1,Boolean>.set_Prop(T1) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C6<T1,Byte>.set_Prop(T1) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C7<>.set_Prop(T1) |
|
||||
| ViableCallable.cs:14:9:14:15 | access to property Prop | C7<Boolean>.set_Prop(bool) |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<Boolean>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<Decimal>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C2<Int32>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C3.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C4<>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C4<Int32>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C5.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<,>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<Boolean,Byte>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<Int32[],Boolean>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<String,Boolean>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<String,Decimal>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<String,Int32>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<T1,Boolean>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C6<T1,Byte>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C7<>.get_Prop() |
|
||||
| ViableCallable.cs:14:19:14:25 | access to property Prop | C7<Boolean>.get_Prop() |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<>.set_Item(T, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<Boolean>.set_Item(bool, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<Decimal>.set_Item(decimal, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C2<Int32>.set_Item(int, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C3.set_Item(decimal, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C4<>.set_Item(bool, T[]) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C4<Int32>.set_Item(bool, int[]) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C5.set_Item(bool, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<,>.set_Item(T2, T1) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<Boolean,Byte>.set_Item(byte, bool) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<Int32[],Boolean>.set_Item(bool, int[]) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<String,Boolean>.set_Item(bool, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<String,Decimal>.set_Item(decimal, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<String,Int32>.set_Item(int, string) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<T1,Boolean>.set_Item(bool, T1) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C6<T1,Byte>.set_Item(byte, T1) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C7<>.set_Item(byte, T1) |
|
||||
| ViableCallable.cs:16:9:16:23 | access to indexer | C7<Boolean>.set_Item(byte, bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<>.get_Item(T) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<Boolean>.get_Item(bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<Decimal>.get_Item(decimal) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C2<Int32>.get_Item(int) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C3.get_Item(decimal) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C4<>.get_Item(bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C4<Int32>.get_Item(bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C5.get_Item(bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<,>.get_Item(T2) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<Boolean,Byte>.get_Item(byte) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<Int32[],Boolean>.get_Item(bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<String,Boolean>.get_Item(bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<String,Decimal>.get_Item(decimal) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<String,Int32>.get_Item(int) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<T1,Boolean>.get_Item(bool) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C6<T1,Byte>.get_Item(byte) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C7<>.get_Item(byte) |
|
||||
| ViableCallable.cs:16:27:16:41 | access to indexer | C7<Boolean>.get_Item(byte) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<>.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<Boolean>.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<Decimal>.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C2<Int32>.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C3.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C4<>.add_Event(EventHandler<T[]>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C4<Int32>.add_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C5.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<,>.add_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<Boolean,Byte>.add_Event(EventHandler<bool>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<Int32[],Boolean>.add_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<String,Boolean>.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<String,Decimal>.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<String,Int32>.add_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<T1,Boolean>.add_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C6<T1,Byte>.add_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C7<>.add_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:18:9:18:16 | access to event Event | C7<Boolean>.add_Event(EventHandler<bool>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<>.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<Boolean>.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<Decimal>.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C2<Int32>.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C3.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C4<>.remove_Event(EventHandler<T[]>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C4<Int32>.remove_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C5.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<,>.remove_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<Boolean,Byte>.remove_Event(EventHandler<bool>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<Int32[],Boolean>.remove_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<String,Boolean>.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<String,Decimal>.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<String,Int32>.remove_Event(EventHandler<string>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<T1,Boolean>.remove_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C6<T1,Byte>.remove_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C7<>.remove_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:19:9:19:16 | access to event Event | C7<Boolean>.remove_Event(EventHandler<bool>) |
|
||||
| ViableCallable.cs:22:9:22:30 | call to method M | C4<>.M<T3>(T[], T3) |
|
||||
| ViableCallable.cs:22:9:22:30 | call to method M | C4<Int32>.M<T3>(int[], T3) |
|
||||
| ViableCallable.cs:22:9:22:30 | call to method M | C6<Int32[],Boolean>.M<T3>(int[], T3) |
|
||||
| ViableCallable.cs:24:9:24:15 | access to property Prop | C4<>.set_Prop(T[]) |
|
||||
| ViableCallable.cs:24:9:24:15 | access to property Prop | C4<Int32>.set_Prop(int[]) |
|
||||
| ViableCallable.cs:24:9:24:15 | access to property Prop | C6<Int32[],Boolean>.set_Prop(int[]) |
|
||||
| ViableCallable.cs:24:19:24:25 | access to property Prop | C4<>.get_Prop() |
|
||||
| ViableCallable.cs:24:19:24:25 | access to property Prop | C4<Int32>.get_Prop() |
|
||||
| ViableCallable.cs:24:19:24:25 | access to property Prop | C6<Int32[],Boolean>.get_Prop() |
|
||||
| ViableCallable.cs:26:9:26:23 | access to indexer | C4<>.set_Item(bool, T[]) |
|
||||
| ViableCallable.cs:26:9:26:23 | access to indexer | C4<Int32>.set_Item(bool, int[]) |
|
||||
| ViableCallable.cs:26:9:26:23 | access to indexer | C6<Int32[],Boolean>.set_Item(bool, int[]) |
|
||||
| ViableCallable.cs:26:27:26:41 | access to indexer | C4<>.get_Item(bool) |
|
||||
| ViableCallable.cs:26:27:26:41 | access to indexer | C4<Int32>.get_Item(bool) |
|
||||
| ViableCallable.cs:26:27:26:41 | access to indexer | C6<Int32[],Boolean>.get_Item(bool) |
|
||||
| ViableCallable.cs:28:9:28:16 | access to event Event | C4<>.add_Event(EventHandler<T[]>) |
|
||||
| ViableCallable.cs:28:9:28:16 | access to event Event | C4<Int32>.add_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:28:9:28:16 | access to event Event | C6<Int32[],Boolean>.add_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:29:9:29:16 | access to event Event | C4<>.remove_Event(EventHandler<T[]>) |
|
||||
| ViableCallable.cs:29:9:29:16 | access to event Event | C4<Int32>.remove_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:29:9:29:16 | access to event Event | C6<Int32[],Boolean>.remove_Event(EventHandler<int[]>) |
|
||||
| ViableCallable.cs:32:30:32:52 | call to method Mock | ViableCallable.Mock<C1<string, int>>() |
|
||||
@@ -264,10 +313,15 @@
|
||||
| ViableCallable.cs:106:9:106:17 | access to event Event2 | C5.remove_Event2(EventHandler<string>) |
|
||||
| ViableCallable.cs:120:9:120:25 | dynamic call to method M2 | C8.M2<decimal>(decimal[]) |
|
||||
| ViableCallable.cs:124:9:124:24 | dynamic call to method M2 | C8.M2<string>(string[]) |
|
||||
| ViableCallable.cs:132:9:132:28 | dynamic call to method M | C6<Boolean,Byte>.M<T3>(bool, T3) |
|
||||
| ViableCallable.cs:132:9:132:28 | dynamic call to method M | C6<T1,Byte>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:134:9:134:14 | dynamic access to member Prop | C6<Boolean,Byte>.set_Prop(bool) |
|
||||
| ViableCallable.cs:134:9:134:14 | dynamic access to member Prop | C6<T1,Byte>.set_Prop(T1) |
|
||||
| ViableCallable.cs:134:18:134:23 | dynamic access to member Prop | C6<Boolean,Byte>.get_Prop() |
|
||||
| ViableCallable.cs:134:18:134:23 | dynamic access to member Prop | C6<T1,Byte>.get_Prop() |
|
||||
| ViableCallable.cs:136:9:136:18 | dynamic access to element | C6<Boolean,Byte>.set_Item(byte, bool) |
|
||||
| ViableCallable.cs:136:9:136:18 | dynamic access to element | C6<T1,Byte>.set_Item(byte, T1) |
|
||||
| ViableCallable.cs:136:22:136:31 | dynamic access to element | C6<Boolean,Byte>.get_Item(byte) |
|
||||
| ViableCallable.cs:136:22:136:31 | dynamic access to element | C6<T1,Byte>.get_Item(byte) |
|
||||
| ViableCallable.cs:138:9:138:52 | ... += ... | C6<T1,Byte>.add_Event(EventHandler<T1>) |
|
||||
| ViableCallable.cs:139:9:139:52 | ... -= ... | C6<T1,Byte>.remove_Event(EventHandler<T1>) |
|
||||
@@ -368,21 +422,29 @@
|
||||
| ViableCallable.cs:195:9:195:152 | call to method InvokeMember | C10.set_Item(int, bool) |
|
||||
| ViableCallable.cs:199:9:199:147 | call to method InvokeMember | C10.add_Event(EventHandler<bool>) |
|
||||
| ViableCallable.cs:200:9:200:150 | call to method InvokeMember | C10.remove_Event(EventHandler<bool>) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C2<>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C2<Boolean>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C2<Decimal>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C2<Int32>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C3.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C4<>.M<T3>(T[], T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C4<Int32>.M<T3>(int[], T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C5.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<,>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<Boolean,Byte>.M<T3>(bool, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<Int32[],Boolean>.M<T3>(int[], T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<String,Boolean>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<String,Decimal>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<String,Int32>.M<T3>(string, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<T1,Boolean>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C6<T1,Byte>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C7<>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:235:9:235:15 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
|
||||
| ViableCallable.cs:284:9:284:15 | call to method M | C6<,>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:284:9:284:15 | call to method M | C7<>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:284:9:284:15 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
|
||||
| ViableCallable.cs:287:9:287:20 | call to method M | C6<,>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:287:9:287:20 | call to method M | C7<>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:287:9:287:20 | call to method M | C7<Boolean>.M<T3>(bool, T3) |
|
||||
| ViableCallable.cs:301:9:301:15 | call to method M | C7<>.M<T3>(T1, T3) |
|
||||
| ViableCallable.cs:304:9:304:20 | call to method M | C7<>.M<T3>(T1, T3) |
|
||||
@@ -401,4 +463,9 @@
|
||||
| ViableCallable.cs:424:9:424:21 | call to method M | C15.A4.M<T1>() |
|
||||
| ViableCallable.cs:424:9:424:21 | call to method M | C15.A5.M<T1>() |
|
||||
| ViableCallable.cs:439:9:439:19 | call to method M1 | C16<String,Int32>.M1(string) |
|
||||
| ViableCallable.cs:442:9:442:24 | call to method M2 | C16<String,Int32>.M2<T>(Func<T>) |
|
||||
| ViableCallable.cs:442:9:442:24 | call to method M2 | C17.M2<T>(Func<T>) |
|
||||
| ViableCallable.cs:450:9:450:21 | call to method M2 | C17.M2<T>(Func<T>) |
|
||||
| ViableCallable.cs:456:9:456:30 | call to method M2 | C16<T,Int32>.M2<T>(Func<T>) |
|
||||
| ViableCallable.cs:456:9:456:30 | call to method M2 | C17.M2<T>(Func<T>) |
|
||||
| ViableCallable.cs:462:9:462:30 | call to method M2 | C16<T,Int32>.M2<T>(Func<T>) |
|
||||
| ViableCallable.cs:462:9:462:30 | call to method M2 | C17.M2<T>(Func<T>) |
|
||||
|
||||
@@ -428,12 +428,12 @@ public class C15
|
||||
abstract class C16<T1, T2>
|
||||
{
|
||||
public virtual T2 M1(T1 x) => throw null;
|
||||
protected virtual T M2<T>(Func<T> x) => x();
|
||||
public virtual T M2<T>(Func<T> x) => x();
|
||||
}
|
||||
|
||||
class C17 : C16<string, int>
|
||||
{
|
||||
void M(int i)
|
||||
void M1(int i)
|
||||
{
|
||||
// Viable callables: C16<string, int>.M1()
|
||||
this.M1("");
|
||||
@@ -441,4 +441,24 @@ class C17 : C16<string, int>
|
||||
// Viable callables: C16<string, int>.M2<int>()
|
||||
this.M2(() => i);
|
||||
}
|
||||
|
||||
public override T M2<T>(Func<T> x) => x();
|
||||
|
||||
void M3<T>(T t, string s) where T : C17
|
||||
{
|
||||
// Viable callable: C17.M2()
|
||||
t.M2(() => s);
|
||||
}
|
||||
|
||||
void M4<T>(C16<T, int> c) where T : struct
|
||||
{
|
||||
// Viable callable: C16.M2() [also reports C17.M2(); false positive]
|
||||
c.M2(() => default(T));
|
||||
}
|
||||
|
||||
void M5<T>(C16<T, int> c) where T : class
|
||||
{
|
||||
// Viable callables: {C16,C17}.M1()
|
||||
c.M2(() => default(T));
|
||||
}
|
||||
}
|
||||
|
||||
33
csharp/ql/test/library-tests/unification/Unification.cs
Normal file
33
csharp/ql/test/library-tests/unification/Unification.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
interface I1 { }
|
||||
|
||||
struct S1 { } struct S2 { }
|
||||
|
||||
class C0 { }
|
||||
class C1<T1> { }
|
||||
class C2<T2> : C1<T2>, I1 where T2 : struct { }
|
||||
class C3<T3> where T3 : class { }
|
||||
class C4<T4> where T4 : C1<C0> { }
|
||||
class C5<T5> where T5 : C1<S1>, I1 { }
|
||||
class C6<T6a, T6b, T6c, T6d> where T6a : C1<T6d> where T6b : T6a, I1 where T6c : C3<T6b> where T6d : struct { }
|
||||
|
||||
class ConstructSomeTypes
|
||||
{
|
||||
C1<S1> f1;
|
||||
C2<S1> f2;
|
||||
C3<C1<S1>> f3;
|
||||
C3<C2<S1>> f4;
|
||||
C4<C1<C0>> f5;
|
||||
C5<C2<S1>> f6;
|
||||
C6<C1<S1>, C2<S1>, C3<C2<S1>>, S1> f7;
|
||||
|
||||
void M<Tm>(C6<C2<S2>, Tm, C3<Tm>, S2> x, C6<C2<S2>, C2<S2>, C3<C2<S2>>, S2> y) where Tm : C2<S2> { }
|
||||
}
|
||||
|
||||
class Tuples<T8, T9>
|
||||
{
|
||||
static (T8, int) t1;
|
||||
static (string, int) t2;
|
||||
static (string, T9) t3;
|
||||
static (T8, T9) t4;
|
||||
static (T8 a, T9 b) t5 = t4;
|
||||
}
|
||||
298
csharp/ql/test/library-tests/unification/Unification.expected
Normal file
298
csharp/ql/test/library-tests/unification/Unification.expected
Normal file
@@ -0,0 +1,298 @@
|
||||
constrainedTypeParameterSubsumes
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<C1<C0>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<C2<S1>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 |
|
||||
| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm |
|
||||
constrainedTypeParameterSubsumptionImpliesUnification
|
||||
constrainedTypeParameterUnifiable
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<C1<C0>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<C2<S1>> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm |
|
||||
| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:10:11:12 | T6a |
|
||||
| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:10:10:10:11 | T5 | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b |
|
||||
| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm |
|
||||
subsumes
|
||||
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:6:7:6:12 | C1<T2> | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<C0> |
|
||||
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<S1> |
|
||||
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<S2> |
|
||||
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:6:7:6:12 | C1<T6d> | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:7:7:7:12 | C2<S1> | Unification.cs:7:7:7:12 | C2<S1> |
|
||||
| Unification.cs:7:7:7:12 | C2<S2> | Unification.cs:7:7:7:12 | C2<S2> |
|
||||
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:7:8:12 | C3<T6b> | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<C1<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<C2<S1>> |
|
||||
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<C2<S2>> |
|
||||
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:7:8:12 | C3<Tm> | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4<> |
|
||||
| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4<C1<C0>> |
|
||||
| Unification.cs:9:7:9:12 | C4<C1<C0>> | Unification.cs:9:7:9:12 | C4<C1<C0>> |
|
||||
| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5<> |
|
||||
| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5<C2<S1>> |
|
||||
| Unification.cs:10:7:10:12 | C5<C2<S1>> | Unification.cs:10:7:10:12 | C5<C2<S1>> |
|
||||
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<,,,> |
|
||||
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
|
||||
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
|
||||
| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
|
||||
| Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> | Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> |
|
||||
| Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
|
||||
| Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> |
|
||||
| Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
|
||||
| Unification.cs:26:7:26:20 | Tuples<,> | Unification.cs:26:7:26:20 | Tuples<,> |
|
||||
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) |
|
||||
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
subsumptionImpliesUnification
|
||||
unifiable
|
||||
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:6:7:6:12 | C1<C0> | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:6:7:6:12 | C1<S1> | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<> |
|
||||
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<T2> |
|
||||
| Unification.cs:6:7:6:12 | C1<S2> | Unification.cs:6:7:6:12 | C1<T6d> |
|
||||
| Unification.cs:7:7:7:12 | C2<S1> | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:7:7:7:12 | C2<S2> | Unification.cs:7:7:7:12 | C2<> |
|
||||
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:7:8:12 | C3<C1<S1>> | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S1>> | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<T6b> |
|
||||
| Unification.cs:8:7:8:12 | C3<C2<S2>> | Unification.cs:8:7:8:12 | C3<Tm> |
|
||||
| Unification.cs:9:7:9:12 | C4<C1<C0>> | Unification.cs:9:7:9:12 | C4<> |
|
||||
| Unification.cs:10:7:10:12 | C5<C2<S1>> | Unification.cs:10:7:10:12 | C5<> |
|
||||
| Unification.cs:11:7:11:28 | C6<C1<S1>,C2<S1>,C3<C2<S1>>,S1> | Unification.cs:11:7:11:28 | C6<,,,> |
|
||||
| Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> | Unification.cs:11:7:11:28 | C6<,,,> |
|
||||
| Unification.cs:11:7:11:28 | C6<C2<S2>,C2<S2>,C3<C2<S2>>,S2> | Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> |
|
||||
| Unification.cs:11:7:11:28 | C6<C2<S2>,Tm,C3<Tm>,S2> | Unification.cs:11:7:11:28 | C6<,,,> |
|
||||
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:30:12:30:23 | (String,T9) |
|
||||
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:28:12:28:20 | (T8,Int32) |
|
||||
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:31:12:31:19 | (T8,T9) |
|
||||
| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:32:12:32:23 | (T8,T9) |
|
||||
37
csharp/ql/test/library-tests/unification/Unification.ql
Normal file
37
csharp/ql/test/library-tests/unification/Unification.ql
Normal file
@@ -0,0 +1,37 @@
|
||||
import semmle.code.csharp.Unification
|
||||
|
||||
class InterestingType extends Type {
|
||||
InterestingType() {
|
||||
this.fromSource() or
|
||||
this.(TupleType).getAChild() instanceof InterestingType
|
||||
}
|
||||
}
|
||||
|
||||
query predicate constrainedTypeParameterSubsumes(InterestingType tp, InterestingType t) {
|
||||
tp.(Unification::ConstrainedTypeParameter).subsumes(t)
|
||||
}
|
||||
|
||||
// Should be empty
|
||||
query predicate constrainedTypeParameterSubsumptionImpliesUnification(
|
||||
InterestingType tp, InterestingType t
|
||||
) {
|
||||
tp.(Unification::ConstrainedTypeParameter).subsumes(t) and
|
||||
not tp.(Unification::ConstrainedTypeParameter).unifiable(t)
|
||||
}
|
||||
|
||||
query predicate constrainedTypeParameterUnifiable(InterestingType tp, InterestingType t) {
|
||||
tp.(Unification::ConstrainedTypeParameter).unifiable(t)
|
||||
}
|
||||
|
||||
query predicate subsumes(InterestingType t1, InterestingType t2) { Unification::subsumes(t1, t2) }
|
||||
|
||||
// Should be empty
|
||||
query predicate subsumptionImpliesUnification(Type t1, Type t2) {
|
||||
Unification::subsumes(t1, t2) and
|
||||
not Unification::unifiable(t1, t2)
|
||||
}
|
||||
|
||||
query predicate unifiable(InterestingType t1, InterestingType t2) {
|
||||
Unification::unifiable(t1, t2) and
|
||||
not Unification::subsumes(t1, t2)
|
||||
}
|
||||
Reference in New Issue
Block a user