Improve the warning message of incompatible arguments. (#55719)

And fix tests related.
This commit is contained in:
Xinchen Hui 2011-09-23 15:08:11 +00:00
parent f5ec360df7
commit c58f254354
32 changed files with 279 additions and 32 deletions

3
NEWS
View File

@ -1,6 +1,9 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2011, PHP 5.4.0 RC1
- General improvements:
. Improve the warning message of incompatible arguments. (Laruence)
- Core:
. Fixed bug #55707 (undefined reference to `__sync_fetch_and_add_4' on Linux
parisc). (Felipe)

View File

@ -0,0 +1,16 @@
--TEST--
Bug #55719 (Argument restriction should come with a more specific error message)
--FILE--
<?php
Class Base {
public function &test($foo, array $bar, $option = NULL, $extra = "lllllllllllllllllllllllllllllllllllllllllllllllllll") {
}
}
class Sub extends Base {
public function &test() {
}
}
?>
--EXPECTF--
Strict Standards: Declaration of Sub::test() should be compatible with & Base::test($foo, array $bar, $option = NULL, $extra = 'llllllllll...') in %sargument_restriction_001.php on line %d

View File

@ -0,0 +1,16 @@
--TEST--
Bug #55719 (Argument restriction should come with a more specific error message)
--FILE--
<?php
Abstract Class Base {
public function test($foo, array &$bar, $option = NULL, $extra = 3.141592653589793238462643383279502884197169399375105 ) {
}
}
class Sub extends Base {
public function test($foo, array &$bar) {
}
}
?>
--EXPECTF--
Strict Standards: Declaration of Sub::test() should be compatible with Base::test($foo, array &$bar, $option = NULL, $extra = 3.1415926535898) in %sargument_restriction_002.php on line %d

View File

@ -0,0 +1,19 @@
--TEST--
Bug #55719 (Argument restriction should come with a more specific error message)
--FILE--
<?php
class Foo {
}
Abstract Class Base {
public function test(Foo $foo, array $bar, $option = NULL, $extra = "lllllllllllllllllllllllllllllllllllllllllllllllllll") {
}
}
class Sub extends Base {
public function test() {
}
}
?>
--EXPECTF--
Strict Standards: Declaration of Sub::test() should be compatible with Base::test(Foo $foo, array $bar, $option = NULL, $extra = 'llllllllll...') in %sargument_restriction_003.php on line %d

View File

@ -0,0 +1,17 @@
--TEST--
Bug #55719 (Argument restriction should come with a more specific error message)
--FILE--
<?php
class Foo {
}
Abstract Class Base {
abstract public function test(Foo $foo, array $bar, $option = NULL, $extra = 16777215) ;
}
class Sub extends Base {
public function test(Foo $foo, array $bar, $option = NULL, $extra = 0xffffff ) {
}
}
?>
--EXPECTF--

View File

@ -0,0 +1,11 @@
--TEST--
Bug #55719 (Argument restriction should come with a more specific error message)
--FILE--
<?php
class Sub implements ArrayAccess {
public function offsetSet() {
}
}
?>
--EXPECTF--
Fatal error: Declaration of Sub::offsetSet() must be compatible with ArrayAccess::offsetSet($offset, $value) in %sargument_restriction_005.php on line %d

View File

@ -14,6 +14,6 @@ class b implements a { function f($a=1) {}}
class c extends b {function f() {}}
?>
--EXPECTF--
string(62) "Declaration of c::f() should be compatible with that of b::f()"
string(60) "Declaration of c::f() should be compatible with b::f($a = 1)"

View File

@ -15,4 +15,4 @@ class Test extends TestInterface {
?>
--EXPECTF--
Fatal error: Declaration of Test::__construct() must be compatible with that of TestInterface::__construct() in %s on line %d
Fatal error: Declaration of Test::__construct() must be compatible with TestInterface::__construct(ExampleClass $var) in %s on line %d

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with test::foo() in %s on line %d
Done

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with test::foo($arg) in %s on line %d
Done

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with test::foo($arg) in %s on line %d
Done

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with & test::foo() in %s on line %d
Done

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with test::foo($arg, $arg2 = NULL) in %s on line %d
Done

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with test::foo($arg, &$arg2 = NULL) in %s on line %d
Done

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with test::foo(Test $arg) in %s on line %d
Done

View File

@ -20,5 +20,5 @@ class test3 extends test {
echo "Done\n";
?>
--EXPECTF--
Strict Standards: Declaration of test3::foo() should be compatible with that of test::foo() in %s on line %d
Strict Standards: Declaration of test3::foo() should be compatible with test::foo(Test $arg) in %s on line %d
Done

View File

@ -35,4 +35,4 @@ $o->sayHello(array());
--EXPECTF--
World!
Fatal error: Declaration of MyHelloWorld::sayHello() must be compatible with that of Base::sayHello() in %s on line %d
Fatal error: Declaration of MyHelloWorld::sayHello() must be compatible with Base::sayHello(array $a) in %s on line %d

View File

@ -3010,7 +3010,169 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
}
/* }}} */
static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC)
#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
if (UNEXPECTED(offset - buf + size >= length)) { \
length += size + 1; \
buf = erealloc(buf, length); \
}
static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
{
char *offset, *buf;
zend_uint length = 1024;
offset = buf = (char *)emalloc(length * sizeof(char));
if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
*(offset++) = '&';
*(offset++) = ' ';
}
if (fptr->common.scope) {
memcpy(offset, fptr->common.scope->name, fptr->common.scope->name_length);
offset += fptr->common.scope->name_length;
*(offset++) = ':';
*(offset++) = ':';
}
{
size_t name_len = strlen(fptr->common.function_name);
REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
memcpy(offset, fptr->common.function_name, name_len);
offset += name_len;
}
*(offset++) = '(';
if (fptr->common.arg_info) {
zend_uint i, required;
zend_arg_info *arg_info = fptr->common.arg_info;
required = fptr->common.required_num_args;
for (i = 0; i < fptr->common.num_args;) {
if (arg_info->class_name) {
REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->class_name_len);
memcpy(offset, arg_info->class_name, arg_info->class_name_len);
offset += arg_info->class_name_len;
*(offset++) = ' ';
} else if (arg_info->type_hint) {
zend_uint type_name_len;
char *type_name = zend_get_type_by_const(arg_info->type_hint);
type_name_len = strlen(type_name);
REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
memcpy(offset, type_name, type_name_len);
offset += type_name_len;
*(offset++) = ' ';
}
if (arg_info->pass_by_reference) {
*(offset++) = '&';
}
*(offset++) = '$';
if (arg_info->name) {
REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
memcpy(offset, arg_info->name, arg_info->name_len);
offset += arg_info->name_len;
} else {
zend_uint idx = i;
memcpy(offset, "param", 5);
offset += 5;
do {
*(offset++) = (char) (idx % 10) + '0';
idx /= 10;
} while (idx > 0);
}
if (i >= required) {
*(offset++) = ' ';
*(offset++) = '=';
*(offset++) = ' ';
if (fptr->type == ZEND_USER_FUNCTION) {
zend_op *precv = NULL;
{
zend_uint idx = i;
zend_op *op = ((zend_op_array *)fptr)->opcodes;
zend_op *end = op + ((zend_op_array *)fptr)->last;
++idx;
while (op < end) {
if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
&& op->op1.num == (long)idx)
{
precv = op;
}
++op;
}
}
if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
zval *zv, zv_copy;
int use_copy;
ALLOC_ZVAL(zv);
*zv = *precv->op2.zv;
zval_copy_ctor(zv);
INIT_PZVAL(zv);
zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC);
if (Z_TYPE_P(zv) == IS_BOOL) {
if (Z_LVAL_P(zv)) {
memcpy(offset, "true", 4);
offset += 4;
} else {
memcpy(offset, "false", 5);
offset += 5;
}
} else if (Z_TYPE_P(zv) == IS_NULL) {
memcpy(offset, "NULL", 4);
offset += 4;
} else if (Z_TYPE_P(zv) == IS_STRING) {
*(offset++) = '\'';
REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
offset += MIN(Z_STRLEN_P(zv), 10);
if (Z_STRLEN_P(zv) > 10) {
*(offset++) = '.';
*(offset++) = '.';
*(offset++) = '.';
}
*(offset++) = '\'';
} else {
zend_make_printable_zval(zv, &zv_copy, &use_copy);
if (Z_TYPE_P(zv) == IS_STRING) {
REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), Z_STRLEN_P(zv)));
memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
offset += Z_STRLEN_P(zv);
} else if (Z_TYPE_P(zv) == IS_LONG) {
REALLOC_BUF_IF_EXCEED(buf, offset, length, 21);
offset += zend_sprintf(offset, "%ld", Z_LVAL_P(zv));
} else if (Z_TYPE_P(zv) == IS_DOUBLE) {
REALLOC_BUF_IF_EXCEED(buf, offset, length, 21);
offset += zend_sprintf(offset, "%.*G", (int) EG(precision), Z_DVAL_P(zv));
}
if (use_copy) {
zval_dtor(&zv_copy);
}
}
zval_ptr_dtor(&zv);
}
} else {
memcpy(offset, "NULL", 4);
offset += 4;
}
}
if (++i < fptr->common.num_args) {
*(offset++) = ',';
*(offset++) = ' ';
}
arg_info++;
REALLOC_BUF_IF_EXCEED(buf, offset, length, 23);
}
}
*(offset++) = ')';
*offset = '\0';
return buf;
}
/* }}} */
static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
{
zend_uint child_flags;
zend_uint parent_flags = parent->common.fn_flags;
@ -3069,14 +3231,17 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with that of %s::%s()", ZEND_FN_SCOPE_NAME(child), child->common.function_name, ZEND_FN_SCOPE_NAME(child->common.prototype), child->common.prototype->common.function_name);
zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
}
} else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with that of %s::%s()", ZEND_FN_SCOPE_NAME(child), child->common.function_name, ZEND_FN_SCOPE_NAME(parent), parent->common.function_name);
char *method_prototype = zend_get_function_declaration(child->common.prototype TSRMLS_CC);
zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
efree(method_prototype);
}
}
}
/* }}} */
static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, const zend_hash_key *hash_key, zend_class_entry *child_ce) /* {{{ */
{

View File

@ -14,4 +14,4 @@ class bar extends php_user_filter {
}
?>
--EXPECTF--
Strict Standards: Declaration of bar::filter() should be compatible with that of php_user_filter::filter() in %s on line %d
Strict Standards: Declaration of bar::filter() should be compatible with php_user_filter::filter($in, $out, &$consumed, $closing) in %s on line %d

View File

@ -9,4 +9,4 @@ class foo extends php_user_filter {
}
?>
--EXPECTF--
Strict Standards: Declaration of foo::filter() should be compatible with that of php_user_filter::filter() in %s on line %d
Strict Standards: Declaration of foo::filter() should be compatible with php_user_filter::filter($in, $out, &$consumed, $closing) in %s on line %d

View File

@ -9,4 +9,4 @@ class foo extends php_user_filter {
}
?>
--EXPECTF--
Strict Standards: Declaration of foo::onCreate() should be compatible with that of php_user_filter::onCreate() in %s on line %d
Strict Standards: Declaration of foo::onCreate() should be compatible with php_user_filter::onCreate() in %s on line %d

View File

@ -16,4 +16,4 @@ class implem implements constr
?>
--EXPECTF--
Fatal error: Declaration of implem::__construct() must be compatible with that of constr::__construct() in %s on line %d
Fatal error: Declaration of implem::__construct() must be compatible with constr::__construct() in %s on line %d

View File

@ -20,4 +20,4 @@ class derived extends implem
?>
--EXPECTF--
Fatal error: Declaration of derived::__construct() must be compatible with that of constr::__construct() in %s on line %d
Fatal error: Declaration of derived::__construct() must be compatible with constr::__construct() in %s on line %d

View File

@ -23,4 +23,4 @@ class derived extends implem
?>
--EXPECTF--
Fatal error: Declaration of derived::__construct() must be compatible with that of constr::__construct() in %s on line %d
Fatal error: Declaration of derived::__construct() must be compatible with constr::__construct() in %s on line %d

View File

@ -17,5 +17,5 @@ class B extends A
===DONE===
--EXPECTF--
Strict Standards: Declaration of B::f() should be compatible with that of A::f() in %sinheritance_003.php on line %d
Strict Standards: Declaration of B::f() should be compatible with A::f($x) in %sinheritance_003.php on line %d
===DONE===

View File

@ -17,5 +17,5 @@ class B extends A
===DONE===
--EXPECTF--
Strict Standards: Declaration of B::f() should be compatible with that of A::f() in %sinheritance_004.php on line %d
Strict Standards: Declaration of B::f() should be compatible with A::f() in %sinheritance_004.php on line %d
===DONE===

View File

@ -28,6 +28,6 @@ $b->foo(1);
?>
--EXPECTF--
Strict Standards: Declaration of C::foo() should be compatible with that of A::foo() in %s on line %d
Strict Standards: Declaration of C::foo() should be compatible with A::foo($arg1 = 1) in %s on line %d
int(1)
int(3)

View File

@ -18,5 +18,5 @@ $b->foo();
?>
--EXPECTF--
Strict Standards: Declaration of B::foo() should be compatible with that of A::foo() in %s on line %d
Strict Standards: Declaration of B::foo() should be compatible with A::foo($arg = 1) in %s on line %d
foo

View File

@ -12,7 +12,7 @@ Class D2 extends C { function f(SomeClass $a) {} }
?>
==DONE==
--EXPECTF--
Strict Standards: Declaration of D2::f() should be compatible with that of C::f() in %s on line 8
Strict Standards: Declaration of D2::f() should be compatible with C::f(array $a) in %s on line 8
Compatible hint.
Class hint, should be array.
==DONE==
==DONE==

View File

@ -9,6 +9,6 @@ Class D extends C { function f($a) {} }
?>
==DONE==
--EXPECTF--
Strict Standards: Declaration of D::f() should be compatible with that of C::f() in %s on line 5
Strict Standards: Declaration of D::f() should be compatible with C::f(array $a) in %s on line 5
No hint, should be array.
==DONE==
==DONE==

View File

@ -9,6 +9,6 @@ Class D extends C { function f(array $a) {} }
?>
==DONE==
--EXPECTF--
Strict Standards: Declaration of D::f() should be compatible with that of C::f() in %s on line 5
Strict Standards: Declaration of D::f() should be compatible with C::f(SomeClass $a) in %s on line 5
Array hint, should be class.
==DONE==
==DONE==

View File

@ -9,6 +9,6 @@ Class D extends C { function f(array $a) {} }
?>
==DONE==
--EXPECTF--
Strict Standards: Declaration of D::f() should be compatible with that of C::f() in %s on line 5
Strict Standards: Declaration of D::f() should be compatible with C::f($a) in %s on line 5
Array hint, should be nothing.
==DONE==
==DONE==