@@ -883,6 +883,17 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b
883883 )
884884 )
885885 )
886+ or
887+ // A write to a dynamic property
888+ exists ( DynamicMemberAccess dma , AssignableDefinition def , DynamicProperty dp |
889+ def .getTargetAccess ( ) = dma and
890+ dp .getAnAccess ( ) = dma and
891+ c .isDynamicProperty ( dp ) and
892+ src = def .getSource ( ) and
893+ q = dma .getQualifier ( ) and
894+ e = def .getExpr ( ) and
895+ postUpdate = true
896+ )
886897}
887898
888899/**
@@ -894,6 +905,18 @@ private predicate fieldOrPropertyRead(Expr e1, ContentSet c, FieldOrPropertyRead
894905 c = e2 .getTarget ( ) .( FieldOrProperty ) .getContentSet ( )
895906}
896907
908+ /**
909+ * Holds if `e2` is an expression that reads the dynamic property `c` from
910+ * expression `e1`.
911+ */
912+ private predicate dynamicPropertyRead ( Expr e1 , ContentSet c , DynamicMemberRead e2 ) {
913+ exists ( DynamicPropertyContent dpc |
914+ e1 = e2 .getQualifier ( ) and
915+ dpc .getAnAccess ( ) = e2 and
916+ c .isDynamicProperty ( dpc .getName ( ) )
917+ )
918+ }
919+
897920/**
898921 * Holds if `ce` is a collection expression that adds `src` to the collection `ce`.
899922 */
@@ -1099,6 +1122,8 @@ private module Cached {
10991122 |
11001123 fieldOrPropertyRead ( e , _, read )
11011124 or
1125+ dynamicPropertyRead ( e , _, read )
1126+ or
11021127 arrayRead ( e , read )
11031128 )
11041129 )
@@ -1140,6 +1165,7 @@ private module Cached {
11401165 newtype TContent =
11411166 TFieldContent ( Field f ) { f .isUnboundDeclaration ( ) } or
11421167 TPropertyContent ( Property p ) { p .isUnboundDeclaration ( ) } or
1168+ TDynamicPropertyContent ( DynamicProperty dp ) or
11431169 TElementContent ( ) or
11441170 TSyntheticFieldContent ( SyntheticField f ) or
11451171 TPrimaryConstructorParameterContent ( Parameter p ) {
@@ -1154,12 +1180,16 @@ private module Cached {
11541180 cached
11551181 newtype TContentSet =
11561182 TSingletonContent ( Content c ) { not c instanceof PropertyContent } or
1157- TPropertyContentSet ( Property p ) { p .isUnboundDeclaration ( ) }
1183+ TPropertyContentSet ( Property p ) { p .isUnboundDeclaration ( ) } or
1184+ TDynamicPropertyContentSet ( DynamicProperty dp )
11581185
11591186 cached
11601187 newtype TContentApprox =
11611188 TFieldApproxContent ( string firstChar ) { firstChar = approximateFieldContent ( _) } or
11621189 TPropertyApproxContent ( string firstChar ) { firstChar = approximatePropertyContent ( _) } or
1190+ TDynamicPropertyApproxContent ( string firstChar ) {
1191+ firstChar = approximateDynamicPropertyContent ( _)
1192+ } or
11631193 TElementApproxContent ( ) or
11641194 TSyntheticFieldApproxContent ( ) or
11651195 TPrimaryConstructorParameterApproxContent ( string firstChar ) {
@@ -2084,6 +2114,18 @@ class FieldOrProperty extends Assignable, Modifiable {
20842114 }
20852115}
20862116
2117+ /** A string that is a reference to a late-bound target of a dynamic member access. */
2118+ class DynamicProperty extends string {
2119+ private DynamicMemberAccess dma ;
2120+
2121+ DynamicProperty ( ) { this = dma .getLateBoundTargetName ( ) }
2122+
2123+ ContentSet getContentSet ( ) { result .isDynamicProperty ( this ) }
2124+
2125+ /** Gets an access of this dynamic property. */
2126+ DynamicMemberAccess getAnAccess ( ) { result = dma }
2127+ }
2128+
20872129private class InstanceFieldOrProperty extends FieldOrProperty {
20882130 InstanceFieldOrProperty ( ) { not this .isStatic ( ) }
20892131}
@@ -2342,6 +2384,11 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration
23422384 or
23432385 exactScope = false and
23442386 isSuccessor = true and
2387+ dynamicPropertyRead ( e1 , _, e2 ) and
2388+ scope = e2
2389+ or
2390+ exactScope = false and
2391+ isSuccessor = true and
23452392 arrayRead ( e1 , e2 ) and
23462393 scope = e2
23472394 or
@@ -2474,6 +2521,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
24742521 exists ( ReadStepConfiguration x | hasNodePath ( x , node1 , node2 ) |
24752522 fieldOrPropertyRead ( node1 .asExpr ( ) , c , node2 .asExpr ( ) )
24762523 or
2524+ dynamicPropertyRead ( node1 .asExpr ( ) , c , node2 .asExpr ( ) )
2525+ or
24772526 node2 .asExpr ( ) .( AwaitExpr ) .getExpr ( ) = node1 .asExpr ( ) and
24782527 c = getResultContent ( )
24792528 )
@@ -3064,6 +3113,11 @@ class ContentApprox extends TContentApprox {
30643113 this = TPropertyApproxContent ( firstChar ) and result = "approximated property " + firstChar
30653114 )
30663115 or
3116+ exists ( string firstChar |
3117+ this = TDynamicPropertyApproxContent ( firstChar ) and
3118+ result = "approximated dynamic property " + firstChar
3119+ )
3120+ or
30673121 this = TElementApproxContent ( ) and result = "element"
30683122 or
30693123 this = TSyntheticFieldApproxContent ( ) and result = "approximated synthetic field"
@@ -3095,6 +3149,11 @@ private string approximatePropertyContent(PropertyContent pc) {
30953149 result = pc .getProperty ( ) .getName ( ) .prefix ( 1 )
30963150}
30973151
3152+ /** Gets a string for approximating the name of a dynamic property. */
3153+ private string approximateDynamicPropertyContent ( DynamicPropertyContent dpc ) {
3154+ result = dpc .getName ( ) .prefix ( 1 )
3155+ }
3156+
30983157/**
30993158 * Gets a string for approximating the name of a synthetic field corresponding
31003159 * to a primary constructor parameter.
@@ -3110,6 +3169,8 @@ ContentApprox getContentApprox(Content c) {
31103169 or
31113170 result = TPropertyApproxContent ( approximatePropertyContent ( c ) )
31123171 or
3172+ result = TDynamicPropertyApproxContent ( approximateDynamicPropertyContent ( c ) )
3173+ or
31133174 c instanceof ElementContent and result = TElementApproxContent ( )
31143175 or
31153176 c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent ( )
0 commit comments