diff --git a/mypy/checker.py b/mypy/checker.py index 0194efe25799c..c69b80a55fd9c 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -7873,7 +7873,7 @@ def warn_deprecated_overload_item( if isinstance(item, Decorator) and isinstance( candidate := item.func.type, CallableType ): - if selftype is not None: + if selftype is not None and not node.is_static: candidate = bind_self(candidate, selftype) if candidate == target: self.warn_deprecated(item.func, context) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 0752fa0b466fb..4b7e39d2042ab 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1485,7 +1485,14 @@ def check_call_expr_with_callee_type( ) proper_callee = get_proper_type(callee_type) if isinstance(e.callee, (NameExpr, MemberExpr)): - self.chk.warn_deprecated_overload_item(e.callee.node, e, target=callee_type) + node = e.callee.node + if node is None and member is not None and isinstance(object_type, Instance): + if (symbol := object_type.type.get(member)) is not None: + node = symbol.node + self.chk.check_deprecated(node, e) + self.chk.warn_deprecated_overload_item( + node, e, target=callee_type, selftype=object_type + ) if isinstance(e.callee, RefExpr) and isinstance(proper_callee, CallableType): # Cache it for find_isinstance_check() if proper_callee.type_guard is not None: diff --git a/test-data/unit/check-deprecated.test b/test-data/unit/check-deprecated.test index 362d8725f1831..df9695332a5bd 100644 --- a/test-data/unit/check-deprecated.test +++ b/test-data/unit/check-deprecated.test @@ -377,6 +377,171 @@ for i in a: # E: function __main__.A.__iter__ is deprecated: no iteration [builtins fixtures/tuple.pyi] +[case testDeprecatedOverloadedInstanceMethods] +# flags: --enable-error-code=deprecated + +from typing import Iterator, Union +from typing_extensions import deprecated, overload + +class A: + @overload + @deprecated("pass `str` instead") + def f(self, v: int) -> None: ... + @overload + def f(self, v: str) -> None: ... + def f(self, v: Union[int, str]) -> None: ... + + @overload + def g(self, v: int) -> None: ... + @overload + @deprecated("pass `int` instead") + def g(self, v: str) -> None: ... + def g(self, v: Union[int, str]) -> None: ... + + @overload + def h(self, v: int) -> A: ... + @overload + def h(self, v: str) -> A: ... + @deprecated("use `h2` instead") + def h(self, v: Union[int, str]) -> A: ... + +class B(A): ... + +a = A() +a.f(1) # E: overload def (self: __main__.A, v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead +a.f("x") +a.g(1) +a.g("x") # E: overload def (self: __main__.A, v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead +a.h(1) # E: function __main__.A.h is deprecated: use `h2` instead +a.h("x") # E: function __main__.A.h is deprecated: use `h2` instead + +b = B() +b.f(1) # E: overload def (self: __main__.A, v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead +b.f("x") +b.g(1) +b.g("x") # E: overload def (self: __main__.A, v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead +b.h(1) # E: function __main__.A.h is deprecated: use `h2` instead +b.h("x") # E: function __main__.A.h is deprecated: use `h2` instead + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedOverloadedClassMethods] +# flags: --enable-error-code=deprecated + +from typing import Iterator, Union +from typing_extensions import deprecated, overload + +class A: + @overload + @classmethod + @deprecated("pass `str` instead") + def f(cls, v: int) -> None: ... + @overload + @classmethod + def f(cls, v: str) -> None: ... + @classmethod + def f(cls, v: Union[int, str]) -> None: ... + + @overload + @classmethod + def g(cls, v: int) -> None: ... + @overload + @classmethod + @deprecated("pass `int` instead") + def g(cls, v: str) -> None: ... + @classmethod + def g(cls, v: Union[int, str]) -> None: ... + + @overload + @classmethod + def h(cls, v: int) -> A: ... + @overload + @classmethod + def h(cls, v: str) -> A: ... + @deprecated("use `h2` instead") + @classmethod + def h(cls, v: Union[int, str]) -> A: ... + +class B(A): ... + +a = A() +a.f(1) # E: overload def (cls: type[__main__.A], v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead +a.f("x") +a.g(1) +a.g("x") # E: overload def (cls: type[__main__.A], v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead +a.h(1) # E: function __main__.A.h is deprecated: use `h2` instead +a.h("x") # E: function __main__.A.h is deprecated: use `h2` instead + +b = B() +b.f(1) # E: overload def (cls: type[__main__.A], v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead +b.f("x") +b.g(1) +b.g("x") # E: overload def (cls: type[__main__.A], v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead +b.h(1) # E: function __main__.A.h is deprecated: use `h2` instead +b.h("x") # E: function __main__.A.h is deprecated: use `h2` instead + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedOverloadedStaticMethods] +# flags: --enable-error-code=deprecated + +from typing import Iterator, Union +from typing_extensions import deprecated, overload + +class A: + @overload + @staticmethod + @deprecated("pass `str` instead") + def f(v: int) -> None: ... + @overload + @staticmethod + def f(v: str) -> None: ... + @staticmethod + def f(v: Union[int, str]) -> None: ... + + @overload + @staticmethod + def g(v: int) -> None: ... + @overload + @staticmethod + @deprecated("pass `int` instead") + def g(v: str) -> None: ... + @staticmethod + def g(v: Union[int, str]) -> None: ... + + @overload + @staticmethod + def h(v: int) -> A: ... + @overload + @staticmethod + def h(v: str) -> A: ... + @deprecated("use `h2` instead") + @staticmethod + def h(v: Union[int, str]) -> A: ... + +class B(A): ... + +a = A() +a.f(1) # E: overload def (v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead +a.f("x") +a.g(1) +a.g("x") # E: overload def (v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead +a.h(1) # E: function __main__.A.h is deprecated: use `h2` instead +a.h("x") # E: function __main__.A.h is deprecated: use `h2` instead + +b = B() +b.f(1) # E: overload def (v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead +b.f("x") +b.g(1) +b.g("x") # E: overload def (v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead +b.h(1) # E: function __main__.A.h is deprecated: use `h2` instead +b.h("x") # E: function __main__.A.h is deprecated: use `h2` instead + +[builtins fixtures/classmethod.pyi] + + [case testDeprecatedOverloadedSpecialMethods] # flags: --enable-error-code=deprecated