@@ -222,27 +222,55 @@ private module Internal {
222222 }
223223 }
224224
225- private class FieldOrProperty extends Assignable {
226- FieldOrProperty ( ) {
227- this instanceof Field or
228- this instanceof Property
225+ private class DynamicFieldOrProperty extends Assignable {
226+ DynamicFieldOrProperty ( ) {
227+ (
228+ this instanceof Field or
229+ this instanceof Property
230+ ) and
231+ this .getName ( ) = any ( DynamicMemberAccess dma ) .getLateBoundTargetName ( )
232+ }
233+
234+ predicate isMemberOf ( string name , ValueOrRefType t ) {
235+ name = this .getName ( ) and t .hasMember ( this )
236+ }
237+ }
238+
239+ private class TypeWithDynamicFieldOrProperty extends ValueOrRefType {
240+ DynamicFieldOrProperty fp ;
241+
242+ TypeWithDynamicFieldOrProperty ( ) { fp .isMemberOf ( _, this ) }
243+
244+ predicate isImplicitlyConvertibleTo ( string name , Type t ) {
245+ name = fp .getName ( ) and
246+ this .isImplicitlyConvertibleTo ( t )
229247 }
230248 }
231249
250+ pragma [ noinline]
251+ private predicate isPossibleDynamicMemberAccessQualifierType (
252+ DynamicMemberAccess dma , string name , TypeWithDynamicFieldOrProperty t
253+ ) {
254+ exists ( Type qt , boolean isExact |
255+ qt = getAPossibleType ( dma .getQualifier ( ) , isExact ) and
256+ name = dma .getLateBoundTargetName ( )
257+ |
258+ isExact = true and t = qt
259+ or
260+ isExact = false and t .isImplicitlyConvertibleTo ( name , qt )
261+ )
262+ }
263+
232264 /**
233265 * Gets a possible type for expression `e`. Simple flow is used to track the
234266 * origin of `e`, and in case `e` is a dynamic member access, only types
235267 * corresponding to the type of a relevant field or property are included.
236268 */
237269 private Type getAPossibleType ( Expr e , boolean isExact ) {
238- exists ( ValueOrRefType qualifierType , FieldOrProperty fp , boolean qualifierTypeIsExact |
239- qualifierType = getAPossibleTypeDynamicMemberAccessQualifier ( e , qualifierTypeIsExact , fp )
270+ exists ( DynamicFieldOrProperty fp , string name , TypeWithDynamicFieldOrProperty t |
271+ isPossibleDynamicMemberAccessQualifierType ( e , name , t ) and
272+ fp .isMemberOf ( name , t )
240273 |
241- (
242- if qualifierTypeIsExact = true
243- then qualifierType .hasMember ( fp )
244- else fp .getDeclaringType ( ) .isImplicitlyConvertibleTo ( qualifierType )
245- ) and
246274 result = fp .getType ( ) and
247275 isExact = false
248276 )
@@ -251,13 +279,6 @@ private module Internal {
251279 result = getASourceType ( e , isExact )
252280 }
253281
254- private Type getAPossibleTypeDynamicMemberAccessQualifier (
255- DynamicMemberAccess dma , boolean isExact , FieldOrProperty fp
256- ) {
257- result = getAPossibleType ( dma .getQualifier ( ) , isExact ) and
258- fp .getName ( ) = dma .getLateBoundTargetName ( )
259- }
260-
261282 /**
262283 * Provides the predicate `getASourceType()` for finding all relevant source
263284 * types for a given expression.
@@ -799,22 +820,14 @@ private module Internal {
799820 // conflicting types (for example, `Tuple<int, string>` is considered
800821 // compatible with `Tuple<T, T>`).
801822 override RuntimeCallable getADynamicTarget ( ) {
802- // Condition 1
803- result = getADynamicTargetCandidate ( ) and
804- // Condition 2
805- forall ( int i | i in [ 0 .. getNumberOfArguments ( ) - 1 ] |
806- result = getADynamicTargetCandidateWithCompatibleArg ( i )
807- )
808- }
809-
810- private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg ( int i ) {
811- result = getADynamicTargetCandidateWithCompatibleArg1 ( i ) or
812- result = getADynamicTargetCandidateWithCompatibleArg2 ( i )
823+ result = this .getADynamicTarget ( this .getNumberOfArguments ( ) - 1 )
813824 }
814825
815- pragma [ noinline]
816- private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg1 ( int i ) {
817- result = this .getADynamicTargetCandidate ( ) and
826+ private RuntimeCallable getADynamicTarget ( int i ) {
827+ i = - 1 and
828+ result = this .getADynamicTargetCandidate ( )
829+ or
830+ result = this .getADynamicTarget ( i - 1 ) and
818831 exists ( Type parameterType , Type argumentType |
819832 parameterType = this .getAParameterType ( result , i ) and
820833 argumentType = getAPossibleType ( this .getArgument ( i ) , _)
@@ -827,6 +840,12 @@ private module Internal {
827840 or
828841 reflectionOrDynamicArgEqualsParamModuloTypeParameters ( argumentType , parameterType )
829842 )
843+ or
844+ result = this .getADynamicTarget ( i - 1 ) and
845+ exists ( Type parameterType , Type t | parameterType = this .getAParameterType ( result , i ) |
846+ this .argumentConvConstExpr ( i , t ) and
847+ t .isImplicitlyConvertibleTo ( parameterType )
848+ )
830849 }
831850
832851 private Type getAParameterType ( RuntimeCallable c , int i ) {
@@ -840,15 +859,6 @@ private module Internal {
840859 )
841860 }
842861
843- pragma [ noinline]
844- private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg2 ( int i ) {
845- result = this .getADynamicTargetCandidate ( ) and
846- exists ( Type parameterType , Type t | parameterType = this .getAParameterType ( result , i ) |
847- this .argumentConvConstExpr ( i , t ) and
848- t .isImplicitlyConvertibleTo ( parameterType )
849- )
850- }
851-
852862 pragma [ noinline]
853863 private predicate argumentConvConstExpr ( int i , Type t ) {
854864 convConstantExpr ( this .getArgument ( i ) , t )
@@ -954,7 +964,7 @@ private module Internal {
954964 */
955965 private predicate isReflectionOrDynamicCallArgumentWithTypeParameters ( Type argType , Type paramType ) {
956966 exists ( DispatchReflectionOrDynamicCall call , Parameter p , int i , int j |
957- p = call .getAStaticTarget ( ) .getParameter ( i ) and
967+ p = call .getADynamicTargetCandidate ( ) .getParameter ( i ) and
958968 (
959969 if p .isParams ( )
960970 then (
0 commit comments