Skip to content

Commit 05d99b0

Browse files
committed
Python: Add test for overloaded __init__ resolution
Adds a test showing that `@typing.overload` stubs are spuriously resolved as call targets alongside the actual `__init__` implementation.
1 parent c9fa7fa commit 05d99b0

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

python/ql/test/library-tests/dataflow/calls-overload/OverloadCallTest.expected

Whitespace-only changes.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Test that `@typing.overload` stubs are not resolved as call targets.
3+
*/
4+
5+
import python
6+
import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch
7+
import utils.test.InlineExpectationsTest
8+
9+
module OverloadCallTest implements TestSig {
10+
string getARelevantTag() { result = "init" }
11+
12+
predicate hasActualResult(Location location, string element, string tag, string value) {
13+
exists(location.getFile().getRelativePath()) and
14+
exists(DataFlowDispatch::DataFlowCall call, Function target, DataFlowDispatch::CallType type |
15+
location = call.getLocation() and
16+
element = call.toString() and
17+
DataFlowDispatch::resolveCall(call.getNode(), target, type) and
18+
target.getName() = "__init__"
19+
|
20+
value = target.getQualifiedName() + ":" + target.getLocation().getStartLine().toString() and
21+
tag = "init"
22+
)
23+
}
24+
}
25+
26+
import MakeTest<OverloadCallTest>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import typing
2+
3+
4+
class OverloadedInit:
5+
@typing.overload
6+
def __init__(self, x: int) -> None: ...
7+
8+
@typing.overload
9+
def __init__(self, x: str, y: str) -> None: ...
10+
11+
def __init__(self, x, y=None):
12+
pass
13+
14+
OverloadedInit(1) # $ init=OverloadedInit.__init__:11 SPURIOUS: init=OverloadedInit.__init__:6 init=OverloadedInit.__init__:9
15+
OverloadedInit("a", "b") # $ init=OverloadedInit.__init__:11 SPURIOUS: init=OverloadedInit.__init__:6 init=OverloadedInit.__init__:9
16+
17+
18+
from typing import overload
19+
20+
21+
class OverloadedInitFromImport:
22+
@overload
23+
def __init__(self, x: int) -> None: ...
24+
25+
@overload
26+
def __init__(self, x: str, y: str) -> None: ...
27+
28+
def __init__(self, x, y=None):
29+
pass
30+
31+
OverloadedInitFromImport(1) # $ init=OverloadedInitFromImport.__init__:28 SPURIOUS: init=OverloadedInitFromImport.__init__:23 init=OverloadedInitFromImport.__init__:26
32+
OverloadedInitFromImport("a", "b") # $ init=OverloadedInitFromImport.__init__:28 SPURIOUS: init=OverloadedInitFromImport.__init__:23 init=OverloadedInitFromImport.__init__:26
33+
34+
35+
class NoOverloads:
36+
def __init__(self, x):
37+
pass
38+
39+
NoOverloads(1) # $ init=NoOverloads.__init__:36

0 commit comments

Comments
 (0)