Skip to content

Commit a4e6433

Browse files
committed
Python: add support for type(self)()
1 parent d43a48c commit a4e6433

File tree

3 files changed

+10
-5
lines changed

3 files changed

+10
-5
lines changed

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ Node classTracker(Class cls) { classTracker(TypeTracker::end(), cls).flowsTo(res
466466
*/
467467
private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) {
468468
t.start() and
469-
result.(CallCfgNode).getFunction() = classTracker(cls)
469+
resolveClassCall(result.(CallCfgNode).asCfgNode(), cls)
470470
or
471471
exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) and
472472
not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
@@ -951,6 +951,12 @@ import MethodCalls
951951
*/
952952
predicate resolveClassCall(CallNode call, Class cls) {
953953
call.getFunction() = classTracker(cls).asCfgNode()
954+
or
955+
// `cls()` inside a classmethod (which also contains `type(self)()` inside a method)
956+
exists(Class classWithMethod |
957+
call.getFunction() = clsTracker(classWithMethod).asCfgNode() and
958+
getADirectSuperclass*(cls) = classWithMethod
959+
)
954960
}
955961

956962
/**

python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ pointsTo_found_typeTracker_notFound
77
| code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func |
88
| code/class_attr_assign.py:11:9:11:25 | ControlFlowNode for Attribute() | my_func |
99
| code/class_attr_assign.py:26:9:26:25 | ControlFlowNode for Attribute() | DummyObject.method |
10-
| code/class_construction.py:23:1:23:11 | ControlFlowNode for Attribute() | X.foo |
1110
| code/class_super.py:50:1:50:6 | ControlFlowNode for Attribute() | outside_def |
1211
| code/conditional_in_argument.py:18:5:18:11 | ControlFlowNode for Attribute() | X.bar |
1312
| code/func_defined_outside_class.py:21:1:21:11 | ControlFlowNode for Attribute() | A.foo |

python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ def foo(self):
88

99
def meth(self):
1010
print("X.meth")
11-
return type(self)(42.1) # $ MISSING: tt=X.__init__ tt=Y.__init__
11+
return type(self)(42.1) # $ tt=X.__init__ tt=Y.__init__
1212

1313
@classmethod
1414
def cm(cls):
1515
print("X.cm")
16-
cls(42.2) # $ MISSING: tt=X.__init__ tt=Y.__init__
16+
cls(42.2) # $ tt=X.__init__ tt=Y.__init__
1717

1818
x = X(42.0) # $ tt=X.__init__
1919
x_421 = x.meth() # $ pt,tt=X.meth
2020
X.cm() # $ pt,tt=X.cm
2121
x.foo() # $ pt,tt=X.foo
2222
print()
23-
x_421.foo() # $ pt=X.foo MISSING: tt=X.foo
23+
x_421.foo() # $ pt=X.foo tt=X.foo
2424
print()
2525

2626

0 commit comments

Comments
 (0)