Skip to content

Commit e247994

Browse files
committed
C#: Overridable operator support in dispatch.
1 parent 8398ee4 commit e247994

File tree

1 file changed

+56
-23
lines changed

1 file changed

+56
-23
lines changed

csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ private module Internal {
7272
not mc.isLateBound()
7373
} or
7474
TDispatchAccessorCall(AccessorCall ac) or
75+
TDispatchOperatorCall(OperatorCall oc) { not oc.isLateBound() } or
7576
TDispatchReflectionCall(MethodCall mc, string name, Expr object, Expr qualifier, int args) {
7677
isReflectionCall(mc, name, object, qualifier, args)
7778
} or
@@ -90,8 +91,6 @@ private module Internal {
9091
or
9192
c instanceof ConstructorInitializer
9293
or
93-
c = any(OperatorCall oc | not oc.isLateBound())
94-
or
9594
c instanceof LocalFunctionCall
9695
}
9796

@@ -113,12 +112,12 @@ private module Internal {
113112
}
114113

115114
cached
116-
predicate mayBenefitFromCallContext(DispatchMethodOrAccessorCall dc) {
115+
predicate mayBenefitFromCallContext(DispatchOverridableCall dc) {
117116
dc.mayBenefitFromCallContext(_, _)
118117
}
119118

120119
cached
121-
RuntimeCallable getADynamicTargetInCallContext(DispatchMethodOrAccessorCall dc, DispatchCall ctx) {
120+
RuntimeCallable getADynamicTargetInCallContext(DispatchOverridableCall dc, DispatchCall ctx) {
122121
result = dc.getADynamicTargetInCallContext(ctx)
123122
}
124123
}
@@ -214,6 +213,9 @@ private module Internal {
214213
/** Gets the qualifier of this call, if any. */
215214
abstract Expr getQualifier();
216215

216+
/** Gets the qualifier or another expression that can be used for typing purposes, if any. */
217+
Expr getSyntheticQualifier() { result = this.getQualifier() }
218+
217219
/** Gets a static (compile-time) target of this call. */
218220
abstract Callable getAStaticTarget();
219221

@@ -241,7 +243,7 @@ private module Internal {
241243
private predicate hasCallable0(Gvn::GvnType t, OverridableCallable c, OverridableCallable source) {
242244
c.getUnboundDeclaration() = source and
243245
any(ValueOrRefType t0 | Gvn::getGlobalValueNumber(t0) = t).hasCallable(c) and
244-
source = any(DispatchMethodOrAccessorCall call).getAStaticTargetExt()
246+
source = any(DispatchOverridableCall call).getAStaticTargetExt()
245247
}
246248

247249
pragma[noinline]
@@ -250,7 +252,7 @@ private module Internal {
250252
hasOverrider(t, c)
251253
}
252254

253-
abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl {
255+
abstract private class DispatchOverridableCall extends DispatchCallImpl {
254256
pragma[noinline]
255257
OverridableCallable getAStaticTargetExt() {
256258
exists(OverridableCallable target | this.getAStaticTarget() = target |
@@ -261,13 +263,15 @@ private module Internal {
261263
}
262264

263265
pragma[nomagic]
264-
predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) }
266+
predicate hasQualifierTypeInherited(Type t) {
267+
t = getAPossibleType(this.getSyntheticQualifier(), _)
268+
}
265269

266270
pragma[noinline]
267271
private predicate hasSubsumedQualifierType(Gvn::GvnType t) {
268272
hasOverrider(t, _) and
269273
exists(Type t0 |
270-
t0 = getAPossibleType(this.getQualifier(), false) and
274+
t0 = getAPossibleType(this.getSyntheticQualifier(), false) and
271275
not t0 instanceof TypeParameter
272276
|
273277
t = Gvn::getGlobalValueNumber(t0)
@@ -280,12 +284,12 @@ private module Internal {
280284
private predicate hasConstrainedTypeParameterQualifierType(
281285
Unification::ConstrainedTypeParameter tp
282286
) {
283-
tp = getAPossibleType(this.getQualifier(), false)
287+
tp = getAPossibleType(this.getSyntheticQualifier(), false)
284288
}
285289

286290
pragma[noinline]
287291
private predicate hasUnconstrainedTypeParameterQualifierType() {
288-
getAPossibleType(this.getQualifier(), false) instanceof
292+
getAPossibleType(this.getSyntheticQualifier(), false) instanceof
289293
Unification::UnconstrainedTypeParameter
290294
}
291295

@@ -313,7 +317,7 @@ private module Internal {
313317
|
314318
pdef = def.getDefinition() and
315319
p = pdef.getTarget() and
316-
this.getQualifier() = def.getARead() and
320+
this.getSyntheticQualifier() = def.getARead() and
317321
p.getPosition() = i and
318322
c.getAParameter() = p and
319323
not p.isParams()
@@ -446,7 +450,7 @@ private module Internal {
446450

447451
pragma[noinline]
448452
NonConstructedOverridableCallable getAViableOverrider0() {
449-
getAPossibleType(this.getQualifier(), false) instanceof TypeParameter and
453+
getAPossibleType(this.getSyntheticQualifier(), false) instanceof TypeParameter and
450454
result.getAConstructingCallableOrSelf() = this.getAStaticTargetExt()
451455
}
452456

@@ -775,7 +779,7 @@ private module Internal {
775779
* The set of viable targets is determined by taking virtual dispatch
776780
* into account.
777781
*/
778-
private class DispatchMethodCall extends DispatchMethodOrAccessorCall, TDispatchMethodCall {
782+
private class DispatchMethodCall extends DispatchOverridableCall, TDispatchMethodCall {
779783
override MethodCall getCall() { this = TDispatchMethodCall(result) }
780784

781785
override Expr getArgument(int i) {
@@ -790,13 +794,35 @@ private module Internal {
790794
override Method getAStaticTarget() { result = this.getCall().getTarget() }
791795
}
792796

797+
/**
798+
* An ordinary operator call.
799+
*
800+
* The set of viable targets is determined by taking virtual dispatch
801+
* into account.
802+
*/
803+
private class DispatchOperatorCall extends DispatchOverridableCall, TDispatchOperatorCall {
804+
override OperatorCall getCall() { this = TDispatchOperatorCall(result) }
805+
806+
override Expr getArgument(int i) { result = this.getCall().getArgument(i) }
807+
808+
/**
809+
* Gets the first child expression of an operator call, which can be considered the qualifier
810+
* expression for the dispatch call use-cases.
811+
*/
812+
override Expr getSyntheticQualifier() { result = this.getCall().getChildExpr(0) }
813+
814+
override Expr getQualifier() { none() }
815+
816+
override Operator getAStaticTarget() { result = this.getCall().getTarget() }
817+
}
818+
793819
/**
794820
* A call to an accessor.
795821
*
796822
* The set of viable targets is determined by taking virtual dispatch
797823
* into account.
798824
*/
799-
private class DispatchAccessorCall extends DispatchMethodOrAccessorCall, TDispatchAccessorCall {
825+
private class DispatchAccessorCall extends DispatchOverridableCall, TDispatchAccessorCall {
800826
override AccessorCall getCall() { this = TDispatchAccessorCall(result) }
801827

802828
override Expr getArgument(int i) { result = this.getCall().getArgument(i) }
@@ -806,7 +832,7 @@ private module Internal {
806832
override Accessor getAStaticTarget() { result = this.getCall().getTarget() }
807833

808834
override RuntimeAccessor getADynamicTarget() {
809-
result = DispatchMethodOrAccessorCall.super.getADynamicTarget() and
835+
result = DispatchOverridableCall.super.getADynamicTarget() and
810836
// Calls to accessors may have `dynamic` expression arguments,
811837
// so we need to check that the types match
812838
forall(Type argumentType, int i | this.hasDynamicArg(i, argumentType) |
@@ -830,7 +856,7 @@ private module Internal {
830856

831857
pragma[nomagic]
832858
private predicate hasQualifierType(Type qualifierType, boolean isExactType) {
833-
exists(Type t | t = getAPossibleType(this.getQualifier(), isExactType) |
859+
exists(Type t | t = getAPossibleType(this.getSyntheticQualifier(), isExactType) |
834860
qualifierType = t and
835861
not t instanceof TypeParameter
836862
or
@@ -1116,7 +1142,8 @@ private module Internal {
11161142

11171143
/** A call using reflection. */
11181144
private class DispatchReflectionCall extends DispatchReflectionOrDynamicCall,
1119-
TDispatchReflectionCall {
1145+
TDispatchReflectionCall
1146+
{
11201147
override MethodCall getCall() { this = TDispatchReflectionCall(result, _, _, _, _) }
11211148

11221149
override string getName() { this = TDispatchReflectionCall(_, result, _, _, _) }
@@ -1164,7 +1191,8 @@ private module Internal {
11641191

11651192
/** A method call using dynamic types. */
11661193
private class DispatchDynamicMethodCall extends DispatchReflectionOrDynamicCall,
1167-
TDispatchDynamicMethodCall {
1194+
TDispatchDynamicMethodCall
1195+
{
11681196
override DynamicMethodCall getCall() { this = TDispatchDynamicMethodCall(result) }
11691197

11701198
override string getName() { result = this.getCall().getLateBoundTargetName() }
@@ -1185,7 +1213,8 @@ private module Internal {
11851213

11861214
/** An operator call using dynamic types. */
11871215
private class DispatchDynamicOperatorCall extends DispatchReflectionOrDynamicCall,
1188-
TDispatchDynamicOperatorCall {
1216+
TDispatchDynamicOperatorCall
1217+
{
11891218
override DynamicOperatorCall getCall() { this = TDispatchDynamicOperatorCall(result) }
11901219

11911220
override string getName() {
@@ -1202,7 +1231,8 @@ private module Internal {
12021231

12031232
/** A (potential) call to a property accessor using dynamic types. */
12041233
private class DispatchDynamicMemberAccess extends DispatchReflectionOrDynamicCall,
1205-
TDispatchDynamicMemberAccess {
1234+
TDispatchDynamicMemberAccess
1235+
{
12061236
override DynamicMemberAccess getCall() { this = TDispatchDynamicMemberAccess(result) }
12071237

12081238
override string getName() {
@@ -1226,7 +1256,8 @@ private module Internal {
12261256

12271257
/** A (potential) call to an indexer accessor using dynamic types. */
12281258
private class DispatchDynamicElementAccess extends DispatchReflectionOrDynamicCall,
1229-
TDispatchDynamicElementAccess {
1259+
TDispatchDynamicElementAccess
1260+
{
12301261
override DynamicElementAccess getCall() { this = TDispatchDynamicElementAccess(result) }
12311262

12321263
override string getName() {
@@ -1252,7 +1283,8 @@ private module Internal {
12521283

12531284
/** A (potential) call to an event accessor using dynamic types. */
12541285
private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall,
1255-
TDispatchDynamicEventAccess {
1286+
TDispatchDynamicEventAccess
1287+
{
12561288
override AssignArithmeticOperation getCall() {
12571289
this = TDispatchDynamicEventAccess(result, _, _)
12581290
}
@@ -1269,7 +1301,8 @@ private module Internal {
12691301

12701302
/** A call to a constructor using dynamic types. */
12711303
private class DispatchDynamicObjectCreation extends DispatchReflectionOrDynamicCall,
1272-
TDispatchDynamicObjectCreation {
1304+
TDispatchDynamicObjectCreation
1305+
{
12731306
override DynamicObjectCreation getCall() { this = TDispatchDynamicObjectCreation(result) }
12741307

12751308
override string getName() { none() }

0 commit comments

Comments
 (0)