@@ -643,9 +643,14 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
643643 if defn .impl :
644644 defn .impl .accept (self )
645645 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+ ):
648652 self .msg .no_overridable_method (defn .name , defn )
653+ self .check_explicit_override_decorator (defn , found_method_base_classes , defn .impl )
649654 self .check_inplace_operator_method (defn )
650655 if not defn .is_property :
651656 self .check_overlapping_overloads (defn )
@@ -972,7 +977,8 @@ def _visit_func_def(self, defn: FuncDef) -> None:
972977 # overload, the legality of the override has already
973978 # been typechecked, and decorated methods will be
974979 # 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 )
976982 self .check_inplace_operator_method (defn )
977983 if defn .original_def :
978984 # Override previous definition.
@@ -1813,23 +1819,41 @@ def expand_typevars(
18131819 else :
18141820 return [(defn , typ )]
18151821
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 :
18171840 """Check if function definition is compatible with base classes.
18181841
18191842 This may defer the method if a signature is not available in at least one base class.
18201843 Return ``None`` if that happens.
18211844
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 .
18231846 """
18241847 # Check against definitions in base classes.
1825- found_base_method = False
1848+ found_method_base_classes : list [ TypeInfo ] = []
18261849 for base in defn .info .mro [1 :]:
18271850 result = self .check_method_or_accessor_override_for_base (defn , base )
18281851 if result is None :
18291852 # Node was deferred, we will have another attempt later.
18301853 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
18331857
18341858 def check_method_or_accessor_override_for_base (
18351859 self , defn : FuncDef | OverloadedFuncDef | Decorator , base : TypeInfo
@@ -4739,9 +4763,14 @@ def visit_decorator(self, e: Decorator) -> None:
47394763 self .check_incompatible_property_override (e )
47404764 # For overloaded functions we already checked override for overload as a whole.
47414765 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+ ):
47444772 self .msg .no_overridable_method (e .func .name , e .func )
4773+ self .check_explicit_override_decorator (e .func , found_method_base_classes )
47454774
47464775 if e .func .info and e .func .name in ("__init__" , "__new__" ):
47474776 if e .type and not isinstance (get_proper_type (e .type ), (FunctionLike , AnyType )):
0 commit comments