@@ -237,6 +237,124 @@ def set_attr(obj):
237
237
SINK (y .attr ) # $ MISSING: flow
238
238
SINK_F (z .attr ) # $ MISSING: flow
239
239
240
+ # ------------------------------------------------------------------------------
241
+ # Content in class attribute
242
+ # ------------------------------------------------------------------------------
243
+
244
+ class WithTuple :
245
+ my_tuple = (SOURCE , NONSOURCE )
246
+
247
+ def test_inst (self ):
248
+ SINK (self .my_tuple [0 ]) # $ MISSING: flow
249
+ SINK_F (self .my_tuple [1 ])
250
+
251
+ def test_inst_no_call (self ):
252
+ SINK (self .my_tuple [0 ]) # $ MISSING: flow
253
+ SINK_F (self .my_tuple [1 ])
254
+
255
+ @classmethod
256
+ def test_cm (cls ):
257
+ SINK (cls .my_tuple [0 ]) # $ flow="SOURCE, l:-12 -> cls.my_tuple[0]"
258
+ SINK_F (cls .my_tuple [1 ])
259
+
260
+ @classmethod
261
+ def test_cm_no_call (cls ):
262
+ SINK (cls .my_tuple [0 ]) # $ MISSING: flow="SOURCE, l:-8 -> cls.my_tuple[0]"
263
+ SINK_F (cls .my_tuple [1 ])
264
+
265
+
266
+ @expects (2 * 4 ) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
267
+ def test_WithTuple ():
268
+ SINK (WithTuple .my_tuple [0 ]) # $ flow="SOURCE, l:-23 -> WithTuple.my_tuple[0]"
269
+ SINK_F (WithTuple .my_tuple [1 ])
270
+
271
+ WithTuple .test_cm ()
272
+
273
+ inst = WithTuple ()
274
+ inst .test_inst ()
275
+
276
+ SINK (inst .my_tuple [0 ]) # $ MISSING: flow
277
+ SINK_F (inst .my_tuple [1 ])
278
+
279
+
280
+ @expects (4 ) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
281
+ def test_inst_override ():
282
+ inst = WithTuple ()
283
+
284
+ # setting attribute on instance does not override class attribute, it's only on the
285
+ # instance!
286
+ inst .my_tuple = (NONSOURCE , SOURCE )
287
+
288
+ SINK_F (inst .my_tuple [0 ])
289
+ SINK (inst .my_tuple [1 ]) # $ flow="SOURCE, l:-3 -> inst.my_tuple[1]"
290
+
291
+ SINK (WithTuple .my_tuple [0 ]) # $ flow="SOURCE, l:-46 -> WithTuple.my_tuple[0]"
292
+ SINK_F (WithTuple .my_tuple [1 ])
293
+
294
+
295
+ class WithTuple2 :
296
+ my_tuple = (NONSOURCE ,)
297
+
298
+ def set_to_source ():
299
+ WithTuple2 .my_tuple = (SOURCE ,)
300
+
301
+ @expects (4 ) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
302
+ def test_global_flow_to_class_attribute ():
303
+ inst = WithTuple2 ()
304
+ SINK_F (WithTuple2 .my_tuple [0 ])
305
+ SINK_F (inst .my_tuple [0 ])
306
+
307
+ set_to_source ()
308
+
309
+ SINK (WithTuple2 .my_tuple [0 ]) # $ MISSING: flow="SOURCE, l:-10 -> WithTuple2.my_tuple[0]"
310
+ SINK (inst .my_tuple [0 ]) # $ MISSING: flow="SOURCE, l:-11 -> inst.my_tuple[0]"
311
+
312
+
313
+ class Outer :
314
+ src = SOURCE
315
+ class Inner :
316
+ src = SOURCE
317
+
318
+ @expects (2 ) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
319
+ def test_nested_class ():
320
+ SINK (Outer .src ) # $ flow="SOURCE, l:-6 -> Outer.src"
321
+ SINK (Outer .Inner .src ) # $ flow="SOURCE, l:-5 -> Outer.Inner.src"
322
+
323
+ # --------------------------------------
324
+ # unique classes from functions
325
+ # --------------------------------------
326
+ def make_class ():
327
+ # a fresh class is returned each time this function is called
328
+ class C :
329
+ my_tuple = (NONSOURCE ,)
330
+ return C
331
+
332
+ @expects (8 ) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
333
+ def test_unique_class ():
334
+ # This test highlights that if we use the _ClassExpr_ itself as the target/source
335
+ # for jumpsteps, we will end up with spurious flow (that is, we will think that
336
+ # x_cls and y_cls are the same, so by updating .my_tuple on x_cls we might propagate
337
+ # that to y_cls as well -- it might not matter too much in reality, but certainly an
338
+ # interesting corner case)
339
+ x_cls = make_class ()
340
+ y_cls = make_class ()
341
+
342
+ assert x_cls != y_cls
343
+
344
+ x_inst = x_cls ()
345
+ y_inst = y_cls ()
346
+
347
+ SINK_F (x_cls .my_tuple [0 ])
348
+ SINK_F (x_inst .my_tuple [0 ])
349
+ SINK_F (y_cls .my_tuple [0 ])
350
+ SINK_F (y_inst .my_tuple [0 ])
351
+
352
+ x_cls .my_tuple = (SOURCE ,)
353
+ SINK (x_cls .my_tuple [0 ]) # $ flow="SOURCE, l:-1 -> x_cls.my_tuple[0]"
354
+ SINK (x_inst .my_tuple [0 ]) # $ MISSING: flow="SOURCE, l:-2 -> x_inst.my_tuple[0]"
355
+ SINK_F (y_cls .my_tuple [0 ])
356
+ SINK_F (y_inst .my_tuple [0 ])
357
+
240
358
# ------------------------------------------------------------------------------
241
359
# Crosstalk test -- using different function based on conditional
242
360
# ------------------------------------------------------------------------------
0 commit comments