@@ -117,23 +117,52 @@ private module Cached {
117
117
result = call .( DelegateDataFlowCall ) .getARuntimeTarget ( cc )
118
118
}
119
119
120
+ /**
121
+ * Holds if the set of viable implementations that can be called by `call`
122
+ * might be improved by knowing the call context. This is the case if the
123
+ * call is a delegate call, or if the qualifier accesses a parameter of
124
+ * the enclosing callable `c` (including the implicit `this` parameter).
125
+ */
126
+ private predicate mayBenefitFromCallContext ( DataFlowCall call , Callable c ) {
127
+ c = call .getEnclosingCallable ( ) and
128
+ (
129
+ exists ( CallContext cc | exists ( viableDelegateCallable ( call , cc ) ) |
130
+ not cc instanceof EmptyCallContext
131
+ )
132
+ or
133
+ call .( NonDelegateDataFlowCall ) .getDispatchCall ( ) .mayBenefitFromCallContext ( )
134
+ )
135
+ }
136
+
120
137
/**
121
138
* Holds if the call context `ctx` reduces the set of viable run-time
122
139
* targets of call `call` in `c`.
123
140
*/
124
141
cached
125
142
predicate reducedViableImplInCallContext ( DataFlowCall call , DataFlowCallable c , DataFlowCall ctx ) {
126
- c = viableImpl ( ctx ) and
127
- c = call .getEnclosingCallable ( ) and
128
- exists ( CallContext cc | exists ( viableDelegateCallable ( call , cc ) ) |
129
- not cc instanceof EmptyCallContext
143
+ exists ( int tgts , int ctxtgts |
144
+ mayBenefitFromCallContext ( call , c ) and
145
+ c = viableCallable ( ctx ) and
146
+ ctxtgts = count ( viableImplInCallContext ( call , ctx ) ) and
147
+ tgts = strictcount ( viableImpl ( call ) ) and
148
+ ctxtgts < tgts
130
149
)
131
150
}
132
151
152
+ /**
153
+ * Gets a viable dispatch target of `call` in the context `ctx`. This is
154
+ * restricted to those `call`s for which a context might make a difference.
155
+ */
133
156
private DotNet:: Callable viableImplInCallContext ( DataFlowCall call , DataFlowCall ctx ) {
134
157
exists ( ArgumentCallContext cc | result = viableDelegateCallable ( call , cc ) |
135
158
cc .isArgument ( ctx .getExpr ( ) , _)
136
159
)
160
+ or
161
+ result =
162
+ call
163
+ .( NonDelegateDataFlowCall )
164
+ .getDispatchCall ( )
165
+ .getADynamicTargetInCallContext ( ctx .( NonDelegateDataFlowCall ) .getDispatchCall ( ) )
137
166
}
138
167
139
168
/**
@@ -155,9 +184,10 @@ private module Cached {
155
184
cached
156
185
predicate reducedViableImplInReturn ( DataFlowCallable c , DataFlowCall call ) {
157
186
exists ( int tgts , int ctxtgts |
187
+ mayBenefitFromCallContext ( call , _) and
158
188
c = viableImpl ( call ) and
159
- ctxtgts = strictcount ( DataFlowCall ctx | c = viableImplInCallContext ( call , ctx ) ) and
160
- tgts = strictcount ( DataFlowCall ctx | viableImpl ( ctx ) = call .getEnclosingCallable ( ) ) and
189
+ ctxtgts = count ( DataFlowCall ctx | c = viableImplInCallContext ( call , ctx ) ) and
190
+ tgts = strictcount ( DataFlowCall ctx | viableCallable ( ctx ) = call .getEnclosingCallable ( ) ) and
161
191
ctxtgts < tgts
162
192
)
163
193
}
@@ -278,6 +308,9 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
278
308
279
309
NonDelegateDataFlowCall ( ) { this = TNonDelegateCall ( cfn , dc ) }
280
310
311
+ /** Gets the underlying call. */
312
+ DispatchCall getDispatchCall ( ) { result = dc }
313
+
281
314
override DotNet:: Callable getARuntimeTarget ( ) {
282
315
result = getCallableForDataFlow ( dc .getADynamicTarget ( ) )
283
316
}
0 commit comments