@@ -70,6 +70,12 @@ class TypeTracker extends TTypeTracker {
7070 step = LoadStep ( prop ) and result = MkTypeTracker ( hasCall , "" )
7171 or
7272 exists ( string p | step = StoreStep ( p ) and prop = "" and result = MkTypeTracker ( hasCall , p ) )
73+ or
74+ exists ( PropertySet props |
75+ step = WithoutPropStep ( props ) and
76+ not prop = props .getAProperty ( ) and
77+ result = this
78+ )
7379 }
7480
7581 /** Gets a textual representation of this summary. */
@@ -373,6 +379,26 @@ class SharedTypeTrackingStep extends Unit {
373379 ) {
374380 none ( )
375381 }
382+
383+ /**
384+ * Holds if type-tracking should step from `pred` to `succ` but block flow of `props` through here.
385+ *
386+ * This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
387+ */
388+ predicate withoutPropStep ( DataFlow:: Node pred , DataFlow:: Node succ , PropertySet props ) { none ( ) }
389+ }
390+
391+ /**
392+ * A representative for a set of property names.
393+ *
394+ * Currently this is used to denote a set of properties in `withoutPropStep`.
395+ */
396+ abstract class PropertySet extends string {
397+ bindingset [ this ]
398+ PropertySet ( ) { any ( ) }
399+
400+ /** Gets a property contained in this property set. */
401+ abstract string getAProperty ( ) ;
376402}
377403
378404/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
@@ -413,6 +439,15 @@ module SharedTypeTrackingStep {
413439 ) {
414440 any ( SharedTypeTrackingStep s ) .loadStoreStep ( pred , succ , loadProp , storeProp )
415441 }
442+
443+ /**
444+ * Holds if type-tracking should step from `pred` to `succ` but block flow of `prop` through here.
445+ *
446+ * This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
447+ */
448+ predicate withoutPropStep ( DataFlow:: Node pred , DataFlow:: Node succ , PropertySet props ) {
449+ any ( SharedTypeTrackingStep s ) .withoutPropStep ( pred , succ , props )
450+ }
416451}
417452
418453/**
0 commit comments