Skip to content

Commit 796a606

Browse files
Exclude setters and update tests
1 parent af94ebe commit 796a606

File tree

2 files changed

+17
-14
lines changed

2 files changed

+17
-14
lines changed

python/ql/src/Classes/SubclassShadowing.ql

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,23 @@
1212
* @id py/attribute-shadows-method
1313
*/
1414

15-
/*
16-
* Determine if a class defines a method that is shadowed by an attribute
17-
* defined in a super-class
18-
*/
19-
2015
import python
2116
import semmle.python.ApiGraphs
2217
import semmle.python.dataflow.new.internal.DataFlowDispatch
2318

2419
predicate isSettableProperty(Function prop) {
2520
isProperty(prop) and
26-
exists(Function setter, DataFlow::AttrRead setterRead, FunctionExpr propExpr |
27-
setterRead.asExpr() = setter.getADecorator() and
28-
setterRead.getAttributeName() = "setter" and
29-
propExpr.getInnerScope() = prop and
30-
DataFlow::exprNode(propExpr).(DataFlow::LocalSourceNode).flowsTo(setterRead.getObject())
21+
exists(Function setter |
22+
setter.getScope() = prop.getScope() and
23+
setter.getName() = prop.getName() and
24+
isSetter(setter)
25+
)
26+
}
27+
28+
predicate isSetter(Function f) {
29+
exists(DataFlow::AttrRead attr |
30+
f.getADecorator() = attr.asExpr() and
31+
attr.getAttributeName() = "setter"
3132
)
3233
}
3334

@@ -52,7 +53,8 @@ predicate shadowedBySuperclass(
5253
superShadowed.getName() = shadowed.getName()
5354
) and
5455
// Allow properties if they have setters, as the write in the superclass will call the setter.
55-
not isSettableProperty(shadowed)
56+
not isSettableProperty(shadowed) and
57+
not isSetter(shadowed)
5658
}
5759

5860
from Class cls, Class superclass, DataFlow::AttrWrite write, Function shadowed, string extra
@@ -61,8 +63,8 @@ where
6163
(
6264
if isProperty(shadowed)
6365
then
64-
not isSettableProperty(shadowed) and
65-
extra = " (read-only property may cause an error if written to.)"
66+
// it's not a setter, so it's a read-only property
67+
extra = " (read-only property may cause an error if written to in the superclass.)"
6668
else extra = ""
6769
)
6870
select shadowed, "This method is shadowed by $@ in superclass $@." + extra, write,
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
| subclass_shadowing.py:10:5:10:21 | FunctionExpr | Method shadow is shadowed by an $@ in super class 'Base'. | subclass_shadowing.py:6:9:6:23 | AssignStmt | attribute |
1+
| subclass_shadowing.py:11:5:11:21 | Function shadow | This method is shadowed by $@ in superclass $@. | subclass_shadowing.py:7:9:7:19 | ControlFlowNode for Attribute | attribute shadow | subclass_shadowing.py:4:1:4:11 | Class Base | Base |
2+
| subclass_shadowing.py:41:5:41:18 | Function foo | This method is shadowed by $@ in superclass $@. (read-only property may cause an error if written to.) | subclass_shadowing.py:35:9:35:16 | ControlFlowNode for Attribute | attribute foo | subclass_shadowing.py:33:1:33:12 | Class Base3 | Base3 |

0 commit comments

Comments
 (0)