From 3b349db1a73c83d9f96da5484dd9ff53c2a93367 Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Wed, 25 Sep 2024 13:48:02 -0700 Subject: [PATCH] GH-15992: fix error message for single abstract method not implemented (GH-15993) --- Zend/tests/bug69084.phpt | 2 +- Zend/tests/errmsg_018.phpt | 2 +- .../abstract_get_set_readonly.phpt | 2 +- .../abstract_hook_in_non_abstract_class.phpt | 2 +- .../abstract_hook_not_implemented.phpt | 2 +- .../invalid_abstract_indirect.phpt | 2 +- .../invalid_abstract_indirect_2.phpt | 2 +- .../tests/traits/bugs/abstract-methods01.phpt | 2 +- Zend/tests/traits/interface_002.phpt | 2 +- Zend/zend_inheritance.c | 30 +++++++++++++------ tests/classes/abstract_by_interface_001.phpt | 2 +- tests/classes/abstract_by_interface_002.phpt | 2 +- tests/classes/abstract_derived.phpt | 2 +- tests/classes/abstract_not_declared.phpt | 2 +- tests/classes/abstract_redeclare.phpt | 2 +- tests/classes/abstract_static.phpt | 2 +- .../interface_must_be_implemented.phpt | 2 +- tests/classes/interfaces_002.phpt | 2 +- 18 files changed, 38 insertions(+), 26 deletions(-) diff --git a/Zend/tests/bug69084.phpt b/Zend/tests/bug69084.phpt index 2cefcc54320..8b10ef2fb53 100644 --- a/Zend/tests/bug69084.phpt +++ b/Zend/tests/bug69084.phpt @@ -26,4 +26,4 @@ $b->main(); ?> --EXPECTF-- -Fatal error: Class Bar contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Bar::doOtherStuff) in %s on line %d +Fatal error: Class Bar contains 1 abstract method and must therefore be declared abstract or implement the remaining method (Bar::doOtherStuff) in %s on line %d diff --git a/Zend/tests/errmsg_018.phpt b/Zend/tests/errmsg_018.phpt index 13a0cf45111..070247e4d41 100644 --- a/Zend/tests/errmsg_018.phpt +++ b/Zend/tests/errmsg_018.phpt @@ -10,4 +10,4 @@ class test { echo "Done\n"; ?> --EXPECTF-- -Fatal error: Class test contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (test::foo) in %s on line %d +Fatal error: Class test contains 1 abstract method and must therefore be declared abstract or implement the remaining method (test::foo) in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_get_set_readonly.phpt b/Zend/tests/property_hooks/abstract_get_set_readonly.phpt index 644ffb47496..e8cb95019cc 100644 --- a/Zend/tests/property_hooks/abstract_get_set_readonly.phpt +++ b/Zend/tests/property_hooks/abstract_get_set_readonly.phpt @@ -10,4 +10,4 @@ class C extends P { } ?> --EXPECTF-- -Fatal error: Class C contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (P::$prop::set) in %s on line %d +Fatal error: Class C contains 1 abstract method and must therefore be declared abstract or implement the remaining method (P::$prop::set) in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_hook_in_non_abstract_class.phpt b/Zend/tests/property_hooks/abstract_hook_in_non_abstract_class.phpt index fe27f3ecebc..d3b8396a55f 100644 --- a/Zend/tests/property_hooks/abstract_hook_in_non_abstract_class.phpt +++ b/Zend/tests/property_hooks/abstract_hook_in_non_abstract_class.phpt @@ -12,4 +12,4 @@ class Test { ?> --EXPECTF-- -Fatal error: Class Test contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Test::$prop::get) in %s on line %d +Fatal error: Class Test contains 1 abstract method and must therefore be declared abstract or implement the remaining method (Test::$prop::get) in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_hook_not_implemented.phpt b/Zend/tests/property_hooks/abstract_hook_not_implemented.phpt index bb94c0650b0..24fd4f1ef1e 100644 --- a/Zend/tests/property_hooks/abstract_hook_not_implemented.phpt +++ b/Zend/tests/property_hooks/abstract_hook_not_implemented.phpt @@ -14,4 +14,4 @@ class B extends A {} ?> --EXPECTF-- -Fatal error: Class B contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (A::$prop::get) in %s on line %d +Fatal error: Class B contains 1 abstract method and must therefore be declared abstract or implement the remaining method (A::$prop::get) in %s on line %d diff --git a/Zend/tests/property_hooks/invalid_abstract_indirect.phpt b/Zend/tests/property_hooks/invalid_abstract_indirect.phpt index 834440a7f68..b04d44c8c8a 100644 --- a/Zend/tests/property_hooks/invalid_abstract_indirect.phpt +++ b/Zend/tests/property_hooks/invalid_abstract_indirect.phpt @@ -13,4 +13,4 @@ class B extends A { ?> --EXPECTF-- -Fatal error: Class B contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (A::$prop::get) in %s on line %d +Fatal error: Class B contains 1 abstract method and must therefore be declared abstract or implement the remaining method (A::$prop::get) in %s on line %d diff --git a/Zend/tests/property_hooks/invalid_abstract_indirect_2.phpt b/Zend/tests/property_hooks/invalid_abstract_indirect_2.phpt index 28938c17540..8526562c2ad 100644 --- a/Zend/tests/property_hooks/invalid_abstract_indirect_2.phpt +++ b/Zend/tests/property_hooks/invalid_abstract_indirect_2.phpt @@ -12,4 +12,4 @@ class B extends A { ?> --EXPECTF-- -Fatal error: Class B contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (A::$prop::get) in %s on line %d +Fatal error: Class B contains 1 abstract method and must therefore be declared abstract or implement the remaining method (A::$prop::get) in %s on line %d diff --git a/Zend/tests/traits/bugs/abstract-methods01.phpt b/Zend/tests/traits/bugs/abstract-methods01.phpt index 721f9657594..e50f94ccefe 100644 --- a/Zend/tests/traits/bugs/abstract-methods01.phpt +++ b/Zend/tests/traits/bugs/abstract-methods01.phpt @@ -16,4 +16,4 @@ $test = new TraitsTest(); $test->hello(); ?> --EXPECTF-- -Fatal error: Class %s contains %d abstract method and must therefore be declared abstract or implement the remaining methods (%s) in %s on line %d +Fatal error: Class %s contains %d abstract method and must therefore be declared abstract or implement the remaining method (%s) in %s on line %d diff --git a/Zend/tests/traits/interface_002.phpt b/Zend/tests/traits/interface_002.phpt index bc56a6d68bf..4d48706cc95 100644 --- a/Zend/tests/traits/interface_002.phpt +++ b/Zend/tests/traits/interface_002.phpt @@ -21,4 +21,4 @@ new bar; ?> --EXPECTF-- -Fatal error: Class bar contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (baz::abc) in %s on line %d +Fatal error: Class bar contains 1 abstract method and must therefore be declared abstract or implement the remaining method (baz::abc) in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index f34b8d39323..a3aa58cc235 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -3009,16 +3009,28 @@ void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */ } if (ai.cnt) { - zend_error_noreturn(E_ERROR, !is_explicit_abstract && can_be_abstract - ? "%s %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")" - : "%s %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")", - zend_get_object_type_uc(ce), - ZSTR_VAL(ce->name), ai.cnt, - ai.cnt > 1 ? "s" : "", - DISPLAY_ABSTRACT_FN(0), - DISPLAY_ABSTRACT_FN(1), - DISPLAY_ABSTRACT_FN(2) + if (!is_explicit_abstract && can_be_abstract) { + zend_error_noreturn(E_ERROR, + "%s %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")", + zend_get_object_type_uc(ce), + ZSTR_VAL(ce->name), ai.cnt, + ai.cnt > 1 ? "s" : "", + ai.cnt > 1 ? "s" : "", + DISPLAY_ABSTRACT_FN(0), + DISPLAY_ABSTRACT_FN(1), + DISPLAY_ABSTRACT_FN(2) ); + } else { + zend_error_noreturn(E_ERROR, + "%s %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")", + zend_get_object_type_uc(ce), + ZSTR_VAL(ce->name), ai.cnt, + ai.cnt > 1 ? "s" : "", + DISPLAY_ABSTRACT_FN(0), + DISPLAY_ABSTRACT_FN(1), + DISPLAY_ABSTRACT_FN(2) + ); + } } else { /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */ ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; diff --git a/tests/classes/abstract_by_interface_001.phpt b/tests/classes/abstract_by_interface_001.phpt index a8a6ad31da9..0e165ace25b 100644 --- a/tests/classes/abstract_by_interface_001.phpt +++ b/tests/classes/abstract_by_interface_001.phpt @@ -30,4 +30,4 @@ class Fails extends Root implements MyInterface { object(Leaf)#%d (0) { } -Fatal error: Class Fails contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (MyInterface::MyInterfaceFunc) in %sabstract_by_interface_001.php on line %d +Fatal error: Class Fails contains 1 abstract method and must therefore be declared abstract or implement the remaining method (MyInterface::MyInterfaceFunc) in %sabstract_by_interface_001.php on line %d diff --git a/tests/classes/abstract_by_interface_002.phpt b/tests/classes/abstract_by_interface_002.phpt index 83fc18ad95c..863ae06e7a7 100644 --- a/tests/classes/abstract_by_interface_002.phpt +++ b/tests/classes/abstract_by_interface_002.phpt @@ -30,4 +30,4 @@ class Fails extends Root implements MyInterface { object(Leaf)#%d (0) { } -Fatal error: Class Fails contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (MyInterface::MyInterfaceFunc) in %sabstract_by_interface_002.php on line %d +Fatal error: Class Fails contains 1 abstract method and must therefore be declared abstract or implement the remaining method (MyInterface::MyInterfaceFunc) in %sabstract_by_interface_002.php on line %d diff --git a/tests/classes/abstract_derived.phpt b/tests/classes/abstract_derived.phpt index db040e1342b..11c9125a772 100644 --- a/tests/classes/abstract_derived.phpt +++ b/tests/classes/abstract_derived.phpt @@ -13,4 +13,4 @@ class derived extends base { ?> ===DONE=== --EXPECTF-- -Fatal error: Class derived contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (derived::show) in %sabstract_derived.php on line %d +Fatal error: Class derived contains 1 abstract method and must therefore be declared abstract or implement the remaining method (derived::show) in %sabstract_derived.php on line %d diff --git a/tests/classes/abstract_not_declared.phpt b/tests/classes/abstract_not_declared.phpt index 611cb3cc94c..8f899f0e718 100644 --- a/tests/classes/abstract_not_declared.phpt +++ b/tests/classes/abstract_not_declared.phpt @@ -10,4 +10,4 @@ class fail { echo "Done\n"; // shouldn't be displayed ?> --EXPECTF-- -Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (fail::show) in %s on line %d +Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining method (fail::show) in %s on line %d diff --git a/tests/classes/abstract_redeclare.phpt b/tests/classes/abstract_redeclare.phpt index 843570ba2e1..f8e3d234652 100644 --- a/tests/classes/abstract_redeclare.phpt +++ b/tests/classes/abstract_redeclare.phpt @@ -16,4 +16,4 @@ class fail extends pass { echo "Done\n"; // Shouldn't be displayed ?> --EXPECTF-- -Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (fail::show) in %sabstract_redeclare.php on line %d +Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining method (fail::show) in %sabstract_redeclare.php on line %d diff --git a/tests/classes/abstract_static.phpt b/tests/classes/abstract_static.phpt index 60ff2847848..ab13289ab4c 100644 --- a/tests/classes/abstract_static.phpt +++ b/tests/classes/abstract_static.phpt @@ -31,4 +31,4 @@ echo "Done\n"; // shouldn't be displayed --EXPECTF-- Call to function show() -Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (fail::func) in %sabstract_static.php(%d) : eval()'d code on line %d +Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining method (fail::func) in %sabstract_static.php(%d) : eval()'d code on line %d diff --git a/tests/classes/interface_must_be_implemented.phpt b/tests/classes/interface_must_be_implemented.phpt index 300ace23e3d..8436c663834 100644 --- a/tests/classes/interface_must_be_implemented.phpt +++ b/tests/classes/interface_must_be_implemented.phpt @@ -12,4 +12,4 @@ class derived_a implements if_a { ?> --EXPECTF-- -Fatal error: Class derived_a contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (if_a::f_a) in %s on line %d +Fatal error: Class derived_a contains 1 abstract method and must therefore be declared abstract or implement the remaining method (if_a::f_a) in %s on line %d diff --git a/tests/classes/interfaces_002.phpt b/tests/classes/interfaces_002.phpt index 14ac1f0ffc0..de068b98dc9 100644 --- a/tests/classes/interfaces_002.phpt +++ b/tests/classes/interfaces_002.phpt @@ -23,4 +23,4 @@ echo "Message: " . $foo->getMessage() . "\n"; ?> ===DONE=== --EXPECTF-- -Fatal error: Class Exception_foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (ThrowableInterface::getErrno) in %s on line %d +Fatal error: Class Exception_foo contains 1 abstract method and must therefore be declared abstract or implement the remaining method (ThrowableInterface::getErrno) in %s on line %d