Skip to content

Commit b3056fc

Browse files
Update tests for calls to init + fixes
1 parent 16b90a1 commit b3056fc

File tree

3 files changed

+77
-69
lines changed

3 files changed

+77
-69
lines changed

python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,15 @@ predicate missingCallToSuperclassMethod(Class base, Function shouldCall, string
9595

9696
predicate missingCallToSuperclassMethodRestricted(Class base, Function shouldCall, string name) {
9797
missingCallToSuperclassMethod(base, shouldCall, name) and
98-
not exists(Class subBase |
99-
subBase = getADirectSubclass+(base) and
100-
missingCallToSuperclassMethod(subBase, shouldCall, name)
98+
not exists(Class superBase |
99+
// Alert only on the highest base class that has the issue
100+
superBase = getADirectSuperclass+(base) and
101+
missingCallToSuperclassMethod(superBase, shouldCall, name)
101102
) and
102-
not exists(Function superShouldCall |
103-
superShouldCall.getScope() = getADirectSuperclass+(shouldCall.getScope()) and
104-
missingCallToSuperclassMethod(base, superShouldCall, name)
103+
not exists(Function subShouldCall |
104+
// Mention in the alert only the lowest method we're missing the call to
105+
subShouldCall.getScope() = getADirectSubclass+(shouldCall.getScope()) and
106+
missingCallToSuperclassMethod(base, subShouldCall, name)
105107
)
106108
}
107109

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
| missing_init.py:12:1:12:13 | class B3 | Class B3 may not be initialized properly as $@ is not called from its $@. | missing_init.py:9:5:9:23 | Function __init__ | method B2.__init__ | missing_init.py:14:5:14:23 | Function __init__ | __init__ method |
2-
| missing_init.py:39:1:39:21 | class IUVT | Class IUVT may not be initialized properly as $@ is not called from its $@. | missing_init.py:30:5:30:23 | Function __init__ | method UT.__init__ | missing_init.py:26:5:26:23 | Function __init__ | __init__ method |
3-
| missing_init.py:72:1:72:13 | class AB | Class AB may not be initialized properly as $@ is not called from its $@. | missing_init.py:69:5:69:23 | Function __init__ | method AA.__init__ | missing_init.py:75:5:75:23 | Function __init__ | __init__ method |
1+
| missing_init.py:14:5:14:23 | Function __init__ | This initialization method does not call $@, which may leave $@ partially initialized. | missing_init.py:9:5:9:23 | Function __init__ | B2.__init__ | missing_init.py:13:1:13:13 | Class B3 | B3 |
2+
| missing_init.py:29:5:29:23 | Function __init__ | This initialization method does not call super().__init__, which may cause $@ to be missed during the initialization of $@. | missing_init.py:33:5:33:23 | Function __init__ | UT.__init__ | missing_init.py:42:1:42:21 | Class IUVT | IUVT |
3+
| missing_init.py:70:5:70:23 | Function __init__ | This initialization method does not call $@, which may leave $@ partially initialized. | missing_init.py:64:5:64:23 | Function __init__ | AA.__init__ | missing_init.py:67:1:67:13 | Class AB | AB |
4+
| missing_init.py:124:9:124:27 | Function __init__ | This initialization method does not call $@, which may leave $@ partially initialized. | missing_init.py:117:5:117:23 | Function __init__ | DA.__init__ | missing_init.py:122:5:122:17 | Class DC | DC |
5+
| missing_init.py:134:5:134:23 | Function __init__ | This initialization method does not call $@, which may leave $@ partially initialized. | missing_init.py:117:5:117:23 | Function __init__ | DA.__init__ | missing_init.py:132:1:132:13 | Class DD | DD |

python/ql/test/query-tests/Classes/missing-init/missing_init.py

Lines changed: 64 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22
class B1(object):
33

44
def __init__(self):
5-
do_something()
5+
print("B1 init")
66

77
class B2(B1):
88

99
def __init__(self):
10+
print("B2 init")
1011
B1.__init__(self)
1112

12-
class B3(B2):
13-
14-
def __init__(self):
13+
class B3(B2): # $ Alert
14+
def __init__(self):
15+
print("B3 init")
1516
B1.__init__(self)
1617

18+
B3()
19+
1720
#OK if superclass __init__ is builtin as
1821
#builtin classes tend to rely on __new__
1922
class MyException(Exception):
@@ -23,11 +26,11 @@ def __init__(self):
2326

2427
#ODASA-4107
2528
class IUT(object):
26-
def __init__(self):
29+
def __init__(self):
2730
print("IUT init")
2831

2932
class UT(object):
30-
def __init__(self):
33+
def __init__(self):
3134
print("UT init")
3235

3336
class PU(object):
@@ -36,150 +39,151 @@ class PU(object):
3639
class UVT(UT, PU):
3740
pass
3841

39-
class IUVT(IUT, UVT):
42+
class IUVT(IUT, UVT): # $ Alert
4043
pass
4144

42-
#False positive
45+
print("IUVT")
46+
IUVT()
47+
4348
class M1(object):
4449
def __init__(self):
45-
print("A")
50+
print("M1 init")
4651

4752
class M2(object):
4853
pass
4954

5055
class Mult(M2, M1):
5156
def __init__(self):
52-
super(Mult, self).__init__() # Calls M1.__init__
53-
54-
class X:
55-
def __init__(self):
56-
do_something()
57-
58-
class Y(X):
59-
@decorated
60-
def __init__(self):
61-
X.__init__(self)
57+
print("Mult init")
58+
super(Mult, self).__init__() # OK - Calls M1.__init__
6259

63-
class Z(Y):
64-
def __init__(self):
65-
Y.__init__(self)
60+
Mult()
6661

6762
class AA(object):
6863

6964
def __init__(self):
70-
do_something()
65+
print("AA init")
7166

72-
class AB(AA):
67+
class AB(AA): # $ Alert
7368

74-
#Don't call super class init
75-
def __init__(self):
76-
do_something()
69+
# Doesn't call super class init
70+
def __init__(self):
71+
print("AB init")
7772

7873
class AC(AB):
7974

8075
def __init__(self):
81-
#Missing call to AA.__init__ but not AC's fault.
76+
# Doesn't call AA init, but we don't alert here as the issue is with AB.
77+
print("AC init")
8278
super(AC, self).__init__()
8379

80+
AC()
81+
8482
import six
8583
import abc
8684

8785
class BA(object):
8886

8987
def __init__(self):
90-
do_something()
88+
print("BA init")
9189

9290
@six.add_metaclass(abc.ABCMeta)
9391
class BB(BA):
9492

9593
def __init__(self):
94+
print("BB init")
9695
super(BB,self).__init__()
9796

97+
BB()
98+
9899

99100
@six.add_metaclass(abc.ABCMeta)
100101
class CA(object):
101102

102103
def __init__(self):
103-
do_something()
104+
print("CA init")
104105

105-
class CB(BA):
106+
class CB(CA):
106107

107108
def __init__(self):
109+
print("CB init")
108110
super(CB,self).__init__()
109111

112+
CB()
113+
110114
#ODASA-5799
111115
class DA(object):
112116

113117
def __init__(self):
114-
do_something()
118+
print("DA init")
115119

116120
class DB(DA):
117121

118-
class DC(DA):
122+
class DC(DA): # $ SPURIOUS: Alert # We only consider direct super calls, so have an FP here
119123

120-
def __init__(self):
124+
def __init__(self):
125+
print("DC init")
121126
sup = super(DB.DC, self)
122127
sup.__init__()
123128

129+
DB.DC()
130+
124131
#Simpler variants
125-
class DD(DA):
132+
class DD(DA): # $ SPURIOUS: Alert # We only consider direct super calls, so have an FP here
126133

127-
def __init__(self):
134+
def __init__(self):
135+
print("DD init")
128136
sup = super(DD, self)
129137
sup.__init__()
130138

139+
DD()
140+
131141
class DE(DA):
132142

133-
class DF(DA):
143+
class DF(DA): # No alert here
134144

135-
def __init__(self):
145+
def __init__(self):
146+
print("DF init")
136147
sup = super(DE.DF, self).__init__()
137148

149+
DE.DF()
150+
138151
class FA(object):
139152

140153
def __init__(self):
141-
pass
154+
pass # does nothing, thus is considered a trivial method and ok to not call
142155

143156
class FB(object):
144157

145158
def __init__(self):
146-
do_something()
159+
print("FB init")
147160

148161
class FC(FA, FB):
149162

150163
def __init__(self):
151-
#OK to skip call to FA.__init__ as that does nothing.
164+
# No alert here - ok to skip call to trivial FA init
152165
FB.__init__(self)
153166

154167
#Potential false positives.
155168

156169
class ConfusingInit(B1):
157170

158-
def __init__(self):
171+
def __init__(self): # We track this correctly and don't alert.
159172
super_call = super(ConfusingInit, self).__init__
160173
super_call()
161174

162175

163-
# Library class
164-
import collections
165-
166-
class G1(collections.Counter):
167-
176+
class G1:
168177
def __init__(self):
169-
collections.Counter.__init__(self)
170-
171-
class G2(G1):
178+
print("G1 init")
172179

180+
class G2:
173181
def __init__(self):
174-
super(G2, self).__init__()
182+
print("G2 init")
175183

176-
class G3(collections.Counter):
177-
178-
def __init__(self):
179-
super(G3, self).__init__()
180-
181-
class G4(G3):
182-
183-
def __init__(self):
184-
G3.__init__(self)
184+
class G3(G1, G2):
185+
def __init__(self):
186+
print("G3 init")
187+
for cls in self.__class__.__bases__:
188+
cls.__init__(self) # We dont track which classes this could refer to, but assume it calls all required init methods and don't alert.
185189

0 commit comments

Comments
 (0)