diff --git a/python/ql/test/library-tests/dataflow/calls-overload/OverloadCallTest.expected b/python/ql/test/library-tests/dataflow/calls-overload/OverloadCallTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/dataflow/calls-overload/OverloadCallTest.ql b/python/ql/test/library-tests/dataflow/calls-overload/OverloadCallTest.ql new file mode 100644 index 00000000000..6050f56c0ba --- /dev/null +++ b/python/ql/test/library-tests/dataflow/calls-overload/OverloadCallTest.ql @@ -0,0 +1,26 @@ +/** + * Test that `@typing.overload` stubs are not resolved as call targets. + */ + +import python +import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch +import utils.test.InlineExpectationsTest + +module OverloadCallTest implements TestSig { + string getARelevantTag() { result = "init" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(DataFlowDispatch::DataFlowCall call, Function target | + location = call.getLocation() and + element = call.toString() and + DataFlowDispatch::resolveCall(call.getNode(), target, _) and + target.getName() = "__init__" + | + value = target.getQualifiedName() + ":" + target.getLocation().getStartLine().toString() and + tag = "init" + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/dataflow/calls-overload/test.py b/python/ql/test/library-tests/dataflow/calls-overload/test.py new file mode 100644 index 00000000000..db0e4841936 --- /dev/null +++ b/python/ql/test/library-tests/dataflow/calls-overload/test.py @@ -0,0 +1,39 @@ +import typing + + +class OverloadedInit: + @typing.overload + def __init__(self, x: int) -> None: ... + + @typing.overload + def __init__(self, x: str, y: str) -> None: ... + + def __init__(self, x, y=None): + pass + +OverloadedInit(1) # $ init=OverloadedInit.__init__:11 SPURIOUS: init=OverloadedInit.__init__:6 init=OverloadedInit.__init__:9 +OverloadedInit("a", "b") # $ init=OverloadedInit.__init__:11 SPURIOUS: init=OverloadedInit.__init__:6 init=OverloadedInit.__init__:9 + + +from typing import overload + + +class OverloadedInitFromImport: + @overload + def __init__(self, x: int) -> None: ... + + @overload + def __init__(self, x: str, y: str) -> None: ... + + def __init__(self, x, y=None): + pass + +OverloadedInitFromImport(1) # $ init=OverloadedInitFromImport.__init__:28 SPURIOUS: init=OverloadedInitFromImport.__init__:23 init=OverloadedInitFromImport.__init__:26 +OverloadedInitFromImport("a", "b") # $ init=OverloadedInitFromImport.__init__:28 SPURIOUS: init=OverloadedInitFromImport.__init__:23 init=OverloadedInitFromImport.__init__:26 + + +class NoOverloads: + def __init__(self, x): + pass + +NoOverloads(1) # $ init=NoOverloads.__init__:36