@@ -30,8 +30,28 @@ def test_incompatible_types():
30
30
x .field = str ("Hello" ) # $str=field str SPURIOUS: int=field int
31
31
expects_string (x ) # $ str=field SPURIOUS: int=field
32
32
33
-
33
+ # set in different function
34
+ def set_foo (some_class_instance ): # $ tracked=foo
35
+ some_class_instance .foo = tracked # $ tracked=foo tracked
36
+
37
+ def test_set_x ():
38
+ x = SomeClass () # $ MISSING: tracked=foo
39
+ set_foo (x ) # $ MISSING: tracked=foo
40
+ print (x .foo ) # $ MISSING: tracked=foo tracked
41
+
42
+ # return from a different function
43
+ def create_with_foo ():
44
+ x = SomeClass () # $ tracked=foo
45
+ x .foo = tracked # $ tracked=foo tracked
46
+ return x # $ tracked=foo
47
+
48
+ def test_create_with_foo ():
49
+ x = create_with_foo () # $ tracked=foo
50
+ print (x .foo ) # $ tracked=foo tracked
51
+
52
+ # ------------------------------------------------------------------------------
34
53
# Attributes assigned statically to a class
54
+ # ------------------------------------------------------------------------------
35
55
36
56
class MyClass : # $tracked=field
37
57
field = tracked # $tracked
@@ -40,7 +60,9 @@ class MyClass: # $tracked=field
40
60
instance = MyClass () # $tracked=field
41
61
lookup2 = instance .field # MISSING: tracked
42
62
43
- ## Dynamic attribute access
63
+ # ------------------------------------------------------------------------------
64
+ # Dynamic attribute access
65
+ # ------------------------------------------------------------------------------
44
66
45
67
# Via `getattr`/`setattr`
46
68
@@ -99,3 +121,41 @@ def dunder_dict_indirect_read():
99
121
do_stuff (y ) # $ MISSING: tracked
100
122
101
123
124
+ # ------------------------------------------------------------------------------
125
+ # Tracking of attribute on class instance
126
+ # ------------------------------------------------------------------------------
127
+
128
+ # attribute set in method
129
+ # inspired by https://github.com/github/codeql/pull/6023
130
+
131
+ class MyClass2 (object ):
132
+ def __init__ (self ): # $ tracked=foo
133
+ self .foo = tracked # $ tracked=foo tracked
134
+
135
+ def print_foo (self ): # $ MISSING: tracked=foo
136
+ print (self .foo ) # $ MISSING: tracked=foo tracked
137
+
138
+ def possibly_uncalled_method (self ): # $ MISSING: tracked=foo
139
+ print (self .foo ) # $ MISSING: tracked=foo tracked
140
+
141
+ instance = MyClass2 ()
142
+ print (instance .foo ) # $ MISSING: tracked=foo tracked
143
+ instance .print_foo () # $ MISSING: tracked=foo
144
+
145
+
146
+ # attribute set from outside of class
147
+
148
+ class MyClass3 (object ):
149
+ def print_self (self ): # $ tracked=foo
150
+ print (self ) # $ tracked=foo
151
+
152
+ def print_foo (self ): # $ tracked=foo
153
+ print (self .foo ) # $ tracked=foo tracked
154
+
155
+ def possibly_uncalled_method (self ): # $ MISSING: tracked=foo
156
+ print (self .foo ) # $ MISSING: tracked=foo tracked
157
+
158
+ instance = MyClass3 () # $ tracked=foo
159
+ instance .print_self () # $ tracked=foo
160
+ instance .foo = tracked # $ tracked=foo tracked
161
+ instance .print_foo () # $ tracked=foo
0 commit comments