Skip to content

Commit d273974

Browse files
committed
Python: Don't flag return procedure_call() in __init__ as error
This commit fixes the results for https://lgtm.com/projects/b/jjburton/cgmtools/snapshot/0d8a429b7ea17854a5e5341df98b1cbd54d7fe6c/files/mayaTools/cgm/lib/classes/AttrFactory.py?sort=name&dir=ASC&mode=heatmap#L90 ``` def __init__(...): if error_case: return guiFactory.warning(...) ``` that was wrongly reporting _Explicit return in __init__ method._ as an error.
1 parent 6e50a0e commit d273974

3 files changed

Lines changed: 66 additions & 7 deletions

File tree

python/ql/src/Functions/ExplicitReturnInInit.ql

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212

1313
import python
1414

15-
from Return r
15+
from Return r, Expr rv
1616
where
17-
exists(Function init | init.isInitMethod() and r.getScope() = init and exists(r.getValue())) and
18-
not r.getValue() instanceof None and
19-
not exists(FunctionValue f | f.getACall() = r.getValue().getAFlowNode() | f.neverReturns()) and
17+
exists(Function init | init.isInitMethod() and r.getScope() = init) and
18+
r.getValue() = rv and
19+
not rv.pointsTo(Value::none_()) and
20+
not exists(FunctionValue f | f.getACall() = rv.getAFlowNode() | f.neverReturns()) and
2021
// to avoid double reporting, don't trigger if returning result from other __init__ function
21-
not exists(Attribute meth | meth = r.getValue().(Call).getFunc() | meth.getName() = "__init__")
22+
not exists(Attribute meth | meth = rv.(Call).getFunc() | meth.getName() = "__init__")
2223
select r, "Explicit return in __init__ method."
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
| explicit_return_in_init.py:4:9:4:19 | Return | Explicit return in __init__ method. |
2+
| explicit_return_in_init.py:102:9:102:18 | Return | Explicit return in __init__ method. |

python/ql/test/query-tests/Functions/general/explicit_return_in_init.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class ExplicitReturnInInit(object):
33
def __init__(self):
44
return self
55

6-
#These are OK
6+
# These are OK
77
class ExplicitReturnNoneInInit(object):
88

99
def __init__(self):
@@ -32,7 +32,7 @@ class InitIsGenerator(object):
3232
def __init__(self):
3333
yield self
3434

35-
#OK as it returns result of a call to super().__init__()
35+
# OK as it returns result of a call to super().__init__()
3636
class InitCallsInit(InitCallsError):
3737

3838
def __init__(self):
@@ -43,3 +43,60 @@ class InitCallsBadInit(ExplicitReturnInInit):
4343

4444
def __init__(self):
4545
return ExplicitReturnInInit.__init__(self)
46+
47+
# OK as procedure implicitly returns None
48+
#
49+
# this was seen in the wild: https://lgtm.com/projects/b/jjburton/cgmtools/snapshot/0d8a429b7ea17854a5e5341df98b1cbd54d7fe6c/files/mayaTools/cgm/lib/classes/AttrFactory.py?sort=name&dir=ASC&mode=heatmap#L90
50+
# using a pattern of `return procedure_that_logs_error()`
51+
52+
def procedure():
53+
pass
54+
55+
def explicit_none():
56+
return None
57+
58+
def explicit_none_nested():
59+
return explicit_none()
60+
61+
class InitReturnsCallResult1(object):
62+
63+
def __init__(self):
64+
return procedure()
65+
66+
class InitReturnsCallResult2(object):
67+
68+
def __init__(self):
69+
return explicit_none()
70+
71+
class InitReturnsCallResult3(object):
72+
73+
def __init__(self):
74+
return explicit_none_nested()
75+
76+
class InitReturnsCallResult4(object):
77+
78+
def __init__(self, b):
79+
if b:
80+
p = procedure
81+
else:
82+
p = explicit_none
83+
return p()
84+
85+
class InitReturnsCallResult5(object):
86+
87+
def __init__(self, b):
88+
return procedure() if b else explicit_none()
89+
90+
# Not OK
91+
92+
def not_ok():
93+
return 42
94+
95+
class InitReturnsCallResult6(object):
96+
97+
def __init__(self, b):
98+
if b:
99+
p = procedure_implicit_none()
100+
else:
101+
p = not_ok
102+
return p()

0 commit comments

Comments
 (0)