@@ -643,9 +643,14 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
643
643
if defn .impl :
644
644
defn .impl .accept (self )
645
645
if defn .info :
646
- found_base_method = self .check_method_override (defn )
647
- if defn .is_explicit_override and found_base_method is False :
646
+ found_method_base_classes = self .check_method_override (defn )
647
+ if (
648
+ defn .is_explicit_override
649
+ and not found_method_base_classes
650
+ and found_method_base_classes is not None
651
+ ):
648
652
self .msg .no_overridable_method (defn .name , defn )
653
+ self .check_explicit_override_decorator (defn , found_method_base_classes , defn .impl )
649
654
self .check_inplace_operator_method (defn )
650
655
if not defn .is_property :
651
656
self .check_overlapping_overloads (defn )
@@ -972,7 +977,8 @@ def _visit_func_def(self, defn: FuncDef) -> None:
972
977
# overload, the legality of the override has already
973
978
# been typechecked, and decorated methods will be
974
979
# checked when the decorator is.
975
- self .check_method_override (defn )
980
+ found_method_base_classes = self .check_method_override (defn )
981
+ self .check_explicit_override_decorator (defn , found_method_base_classes )
976
982
self .check_inplace_operator_method (defn )
977
983
if defn .original_def :
978
984
# Override previous definition.
@@ -1813,23 +1819,41 @@ def expand_typevars(
1813
1819
else :
1814
1820
return [(defn , typ )]
1815
1821
1816
- def check_method_override (self , defn : FuncDef | OverloadedFuncDef | Decorator ) -> bool | None :
1822
+ def check_explicit_override_decorator (
1823
+ self ,
1824
+ defn : FuncDef | OverloadedFuncDef ,
1825
+ found_method_base_classes : list [TypeInfo ] | None ,
1826
+ context : Context | None = None ,
1827
+ ) -> None :
1828
+ if (
1829
+ found_method_base_classes
1830
+ and not defn .is_explicit_override
1831
+ and defn .name not in ("__init__" , "__new__" )
1832
+ ):
1833
+ self .msg .explicit_override_decorator_missing (
1834
+ defn .name , found_method_base_classes [0 ].fullname , context or defn
1835
+ )
1836
+
1837
+ def check_method_override (
1838
+ self , defn : FuncDef | OverloadedFuncDef | Decorator
1839
+ ) -> list [TypeInfo ] | None :
1817
1840
"""Check if function definition is compatible with base classes.
1818
1841
1819
1842
This may defer the method if a signature is not available in at least one base class.
1820
1843
Return ``None`` if that happens.
1821
1844
1822
- Return ``True`` if an attribute with the method name was found in the base class .
1845
+ Return a list of base classes which contain an attribute with the method name .
1823
1846
"""
1824
1847
# Check against definitions in base classes.
1825
- found_base_method = False
1848
+ found_method_base_classes : list [ TypeInfo ] = []
1826
1849
for base in defn .info .mro [1 :]:
1827
1850
result = self .check_method_or_accessor_override_for_base (defn , base )
1828
1851
if result is None :
1829
1852
# Node was deferred, we will have another attempt later.
1830
1853
return None
1831
- found_base_method |= result
1832
- return found_base_method
1854
+ if result :
1855
+ found_method_base_classes .append (base )
1856
+ return found_method_base_classes
1833
1857
1834
1858
def check_method_or_accessor_override_for_base (
1835
1859
self , defn : FuncDef | OverloadedFuncDef | Decorator , base : TypeInfo
@@ -4739,9 +4763,14 @@ def visit_decorator(self, e: Decorator) -> None:
4739
4763
self .check_incompatible_property_override (e )
4740
4764
# For overloaded functions we already checked override for overload as a whole.
4741
4765
if e .func .info and not e .func .is_dynamic () and not e .is_overload :
4742
- found_base_method = self .check_method_override (e )
4743
- if e .func .is_explicit_override and found_base_method is False :
4766
+ found_method_base_classes = self .check_method_override (e )
4767
+ if (
4768
+ e .func .is_explicit_override
4769
+ and not found_method_base_classes
4770
+ and found_method_base_classes is not None
4771
+ ):
4744
4772
self .msg .no_overridable_method (e .func .name , e .func )
4773
+ self .check_explicit_override_decorator (e .func , found_method_base_classes )
4745
4774
4746
4775
if e .func .info and e .func .name in ("__init__" , "__new__" ):
4747
4776
if e .type and not isinstance (get_proper_type (e .type ), (FunctionLike , AnyType )):
0 commit comments