@@ -102,7 +102,67 @@ private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) {
102102}
103103
104104/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */
105- predicate levelStep ( Node nodeFrom , Node nodeTo ) { summarizedLocalStep ( nodeFrom , nodeTo ) }
105+ predicate levelStep ( Node nodeFrom , Node nodeTo ) {
106+ summarizedLocalStep ( nodeFrom , nodeTo )
107+ or
108+ localFieldStep ( nodeFrom , nodeTo )
109+ }
110+
111+ /**
112+ * Gets a method of `mod`, with `instance` indicating if this is an instance method.
113+ *
114+ * Does not take inheritance or the various forms of inclusion into account.
115+ */
116+ pragma [ nomagic]
117+ private MethodBase getAMethod ( ModuleBase mod , boolean instance ) {
118+ not mod instanceof SingletonClass and
119+ result = mod .getAMethod ( ) and
120+ if result instanceof SingletonMethod then instance = false else instance = true
121+ or
122+ exists ( SingletonClass cls |
123+ cls .getValue ( ) .( SelfVariableAccess ) .getCfgScope ( ) = mod and
124+ result = cls .getAMethod ( ) .( Method ) and
125+ instance = false
126+ )
127+ }
128+
129+ /**
130+ * Gets a value flowing into `field` in `mod`, with `instance` indicating if it's
131+ * a field on an instance of `mod` (as opposed to the module object itself).
132+ */
133+ pragma [ nomagic]
134+ private Node fieldPredecessor ( ModuleBase mod , boolean instance , string field ) {
135+ exists ( InstanceVariableWriteAccess access , AssignExpr assign |
136+ access .getReceiver ( ) .getCfgScope ( ) = getAMethod ( mod , instance ) and
137+ field = access .getVariable ( ) .getName ( ) and
138+ assign .getLeftOperand ( ) = access and
139+ result .asExpr ( ) .getExpr ( ) = assign .getRightOperand ( )
140+ )
141+ }
142+
143+ /**
144+ * Gets a reference to `field` in `mod`, with `instance` indicating if it's
145+ * a field on an instance of `mod` (as opposed to the module object itself).
146+ */
147+ pragma [ nomagic]
148+ private Node fieldSuccessor ( ModuleBase mod , boolean instance , string field ) {
149+ exists ( InstanceVariableReadAccess access |
150+ access .getReceiver ( ) .getCfgScope ( ) = getAMethod ( mod , instance ) and
151+ result .asExpr ( ) .getExpr ( ) = access and
152+ field = access .getVariable ( ) .getName ( )
153+ )
154+ }
155+
156+ /**
157+ * Holds if `pred -> succ` should be used a level step, from a field assignment to
158+ * a read within the same class.
159+ */
160+ private predicate localFieldStep ( Node pred , Node succ ) {
161+ exists ( ModuleBase mod , boolean instance , string field |
162+ pred = fieldPredecessor ( mod , instance , field ) and
163+ succ = fieldSuccessor ( mod , instance , field )
164+ )
165+ }
106166
107167pragma [ noinline]
108168private predicate argumentPositionMatch (
0 commit comments