mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
C#: Speedup DispatchMethodOrAccessorCall::getAViableOverrider()
In addition to improved performance, the analysis no longer applies a closed-world assumption to type parameters. That is, if the type of a receiver is a type parameter, then the call may target any method of a compatible receiver type, not just the types that actually instantiate the type parameter.
This commit is contained in:
@@ -233,71 +233,61 @@ private module Internal {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasOverrider(OverridableCallable oc, ValueOrRefType t) {
|
||||
exists(oc.getAnOverrider(t))
|
||||
private predicate hasOverrider(OverridableCallable oc, Gvn::GvnType t) {
|
||||
exists(oc.getAnOverrider(any(ValueOrRefType t0 | Gvn::getGlobalValueNumber(t0) = t)))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasCallable(OverridableCallable source, ValueOrRefType t, OverridableCallable c) {
|
||||
private predicate hasCallable(OverridableCallable source, Gvn::GvnType t, OverridableCallable c) {
|
||||
c.getUnboundDeclaration() = source and
|
||||
t.hasCallable(c) and
|
||||
any(ValueOrRefType t0 | Gvn::getGlobalValueNumber(t0) = t).hasCallable(c) and
|
||||
hasOverrider(c, t) 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) {
|
||||
hasOverrider(_, t) and
|
||||
(
|
||||
exists(Type t0, Type t1 |
|
||||
t0 = getAPossibleType(call.getQualifier(), false) and
|
||||
t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()]
|
||||
|
|
||||
t = t1
|
||||
or
|
||||
Unification::subsumes(t1, t)
|
||||
)
|
||||
or
|
||||
constrainedTypeParameterQualifierTypeSubsumes(t,
|
||||
getAConstrainedTypeParameterQualifierType(call))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasQualifierTypeOverridden1(
|
||||
OverridableCallable c, DispatchMethodOrAccessorCall call
|
||||
) {
|
||||
exists(OverridableCallable target | call.getAStaticTarget() = target |
|
||||
c = target.getUnboundDeclaration()
|
||||
or
|
||||
c = target.getAnUltimateImplementor().getUnboundDeclaration()
|
||||
)
|
||||
source = any(DispatchMethodOrAccessorCall call).getAStaticTargetExt()
|
||||
}
|
||||
|
||||
abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl {
|
||||
pragma[noinline]
|
||||
OverridableCallable getAStaticTargetExt() {
|
||||
exists(OverridableCallable target | this.getAStaticTarget() = target |
|
||||
result = target.getUnboundDeclaration()
|
||||
or
|
||||
result = target.getAnUltimateImplementor().getUnboundDeclaration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasSubsumedQualifierType(Gvn::GvnType t) {
|
||||
hasOverrider(_, t) and
|
||||
exists(Type t0 |
|
||||
t0 = getAPossibleType(this.getQualifier(), false) and
|
||||
not t0 instanceof TypeParameter
|
||||
|
|
||||
t = Gvn::getGlobalValueNumber(t0)
|
||||
or
|
||||
Gvn::subsumes(Gvn::getGlobalValueNumber(t0), t)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasConstrainedTypeParameterQualifierType(
|
||||
Unification::ConstrainedTypeParameter tp
|
||||
) {
|
||||
tp = getAPossibleType(this.getQualifier(), false)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasUnconstrainedTypeParameterQualifierType() {
|
||||
getAPossibleType(this.getQualifier(), false) instanceof
|
||||
Unification::UnconstrainedTypeParameter
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) {
|
||||
hasQualifierTypeOverridden0(t, this) and
|
||||
hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c)
|
||||
predicate hasSubsumedQualifierTypeOverridden(Gvn::GvnType t, OverridableCallable c) {
|
||||
this.hasSubsumedQualifierType(t) and
|
||||
hasCallable(any(OverridableCallable oc | oc = this.getAStaticTargetExt()), t, c)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -357,12 +347,33 @@ private module Internal {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Callable getASubsumedStaticTarget0(Type t) {
|
||||
private predicate contextArgHasConstrainedTypeParameterType(
|
||||
DispatchCall ctx, Unification::ConstrainedTypeParameter tp
|
||||
) {
|
||||
this.contextArgHasType(ctx, tp, false)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate contextArgHasUnconstrainedTypeParameterType(DispatchCall ctx) {
|
||||
this.contextArgHasType(ctx, any(Unification::UnconstrainedTypeParameter t), false)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate contextArgHasNonTypeParameterType(DispatchCall ctx, Gvn::GvnType t) {
|
||||
exists(Type t0 |
|
||||
this.contextArgHasType(ctx, t0, false) and
|
||||
not t0 instanceof TypeParameter and
|
||||
t = Gvn::getGlobalValueNumber(t0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Callable getASubsumedStaticTarget0(Gvn::GvnType t) {
|
||||
exists(Callable staticTarget, Type declType |
|
||||
staticTarget = this.getAStaticTarget() and
|
||||
declType = staticTarget.getDeclaringType() and
|
||||
result = staticTarget.getUnboundDeclaration() and
|
||||
Unification::subsumes(declType, t)
|
||||
Gvn::subsumes(Gvn::getGlobalValueNumber(declType), t)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -375,7 +386,8 @@ private module Internal {
|
||||
private Callable getASubsumedStaticTarget() {
|
||||
result = this.getAStaticTarget()
|
||||
or
|
||||
result.getUnboundDeclaration() = this.getASubsumedStaticTarget0(result.getDeclaringType())
|
||||
result.getUnboundDeclaration() =
|
||||
this.getASubsumedStaticTarget0(Gvn::getGlobalValueNumber(result.getDeclaringType()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,6 +438,12 @@ private module Internal {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
NonConstructedOverridableCallable getAViableOverrider0() {
|
||||
getAPossibleType(this.getQualifier(), false) instanceof TypeParameter and
|
||||
result.getAConstructingCallableOrSelf() = this.getAStaticTargetExt()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a callable that is defined in a subtype of the qualifier type of this
|
||||
* call, and which overrides a static target of this call.
|
||||
@@ -468,9 +486,22 @@ private module Internal {
|
||||
*/
|
||||
private RuntimeCallable getAViableOverrider() {
|
||||
exists(ValueOrRefType t, NonConstructedOverridableCallable c |
|
||||
this.hasQualifierTypeOverridden(t, c.getAConstructingCallableOrSelf()) and
|
||||
this.hasSubsumedQualifierTypeOverridden(Gvn::getGlobalValueNumber(t),
|
||||
c.getAConstructingCallableOrSelf()) and
|
||||
result = c.getAnOverrider(t)
|
||||
)
|
||||
or
|
||||
exists(NonConstructedOverridableCallable c |
|
||||
c = this.getAViableOverrider0() and
|
||||
result = c.getAnOverrider(_)
|
||||
|
|
||||
this.hasUnconstrainedTypeParameterQualifierType()
|
||||
or
|
||||
exists(Unification::ConstrainedTypeParameter tp |
|
||||
this.hasConstrainedTypeParameterQualifierType(tp) and
|
||||
tp.subsumes(result.getDeclaringType())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override RuntimeCallable getADynamicTarget() {
|
||||
@@ -510,36 +541,40 @@ private module Internal {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private RuntimeCallable getAViableOverriderInCallContext0(
|
||||
NonConstructedOverridableCallable c, ValueOrRefType t
|
||||
) {
|
||||
result = this.getAViableOverrider() and
|
||||
this.contextArgHasType(_, _, false) and
|
||||
result = c.getAnOverrider(t)
|
||||
private RuntimeCallable getAViableOverriderInCallContext0(Gvn::GvnType t) {
|
||||
exists(NonConstructedOverridableCallable c |
|
||||
result = this.getAViableOverrider() and
|
||||
this.contextArgHasType(_, _, false) and
|
||||
result = c.getAnOverrider(any(Type t0 | t = Gvn::getGlobalValueNumber(t0))) and
|
||||
this.getAStaticTarget() = c.getAConstructingCallableOrSelf()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private RuntimeCallable getAViableOverriderInCallContext1(
|
||||
NonConstructedOverridableCallable c, DispatchCall ctx
|
||||
) {
|
||||
exists(ValueOrRefType t |
|
||||
result = this.getAViableOverriderInCallContext0(c, t) and
|
||||
exists(Type t0, Type t1 |
|
||||
this.contextArgHasType(ctx, t0, false) and
|
||||
t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()]
|
||||
|
|
||||
t = t1
|
||||
or
|
||||
Unification::subsumes(t1, t)
|
||||
)
|
||||
private predicate contextArgHasSubsumedType(DispatchCall ctx, Gvn::GvnType t) {
|
||||
hasOverrider(_, t) and
|
||||
exists(Gvn::GvnType t0 | this.contextArgHasNonTypeParameterType(ctx, t0) |
|
||||
t = t0
|
||||
or
|
||||
Gvn::subsumes(t0, t)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private RuntimeCallable getAViableOverriderInCallContext(DispatchCall ctx) {
|
||||
exists(NonConstructedOverridableCallable c |
|
||||
result = this.getAViableOverriderInCallContext1(c, ctx) and
|
||||
this.getAStaticTarget() = c.getAConstructingCallableOrSelf()
|
||||
exists(Gvn::GvnType t |
|
||||
result = this.getAViableOverriderInCallContext0(t) and
|
||||
this.contextArgHasSubsumedType(ctx, t)
|
||||
)
|
||||
or
|
||||
result = this.getAViableOverrider() and
|
||||
(
|
||||
this.contextArgHasUnconstrainedTypeParameterType(ctx)
|
||||
or
|
||||
exists(Unification::ConstrainedTypeParameter tp |
|
||||
this.contextArgHasConstrainedTypeParameterType(ctx, tp) and
|
||||
tp.subsumes(result.getDeclaringType())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user