diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-03-03 14:21:33 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-03-03 14:23:31 +0100 |
commit | 2c5fcd57c0aa89a00b8caa2acaa04d7ac60a87dd (patch) | |
tree | 6636877193d441d8d0c2c7d75152dfecf5b252e9 /Zend/zend_inheritance.c | |
parent | ef03236d9d1fd3558f70d8920f88b13fb525fed3 (diff) | |
download | php-git-2c5fcd57c0aa89a00b8caa2acaa04d7ac60a87dd.tar.gz |
Resolve trait alias refers to earlier
Make sure all trait method references are converted to absolute
method references in advance. This regresses one error message
that I don't think is particularly valuable.
Diffstat (limited to 'Zend/zend_inheritance.c')
-rw-r--r-- | Zend/zend_inheritance.c | 132 |
1 files changed, 48 insertions, 84 deletions
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index eb79aab098..df84efc389 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1690,9 +1690,9 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z while (alias) { /* Scope unset or equal to the function we compare to, and the alias applies to fn */ if (alias->alias != NULL - && (!aliases[i] || fn->common.scope == aliases[i]) - && ZSTR_LEN(alias->trait_method.method_name) == ZSTR_LEN(fnname) - && (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method.method_name), ZSTR_LEN(alias->trait_method.method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) { + && fn->common.scope == aliases[i] + && zend_string_equals_ci(alias->trait_method.method_name, fnname) + ) { fn_copy = *fn; /* if it is 0, no modifieres has been changed */ @@ -1703,15 +1703,6 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z lcname = zend_string_tolower(alias->alias); zend_add_trait_method(ce, alias->alias, lcname, &fn_copy, overridden); zend_string_release_ex(lcname, 0); - - /* Record the trait from which this alias was resolved. */ - if (!aliases[i]) { - aliases[i] = fn->common.scope; - } - if (!alias->trait_method.class_name) { - /* TODO: try to avoid this assignment (it's necessary only for reflection) */ - alias->trait_method.class_name = zend_string_copy(fn->common.scope->name); - } } alias_ptr++; alias = *alias_ptr; @@ -1732,20 +1723,10 @@ static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, z while (alias) { /* Scope unset or equal to the function we compare to, and the alias applies to fn */ if (alias->alias == NULL && alias->modifiers != 0 - && (!aliases[i] || fn->common.scope == aliases[i]) - && (ZSTR_LEN(alias->trait_method.method_name) == ZSTR_LEN(fnname)) - && (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method.method_name), ZSTR_LEN(alias->trait_method.method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) { - + && fn->common.scope == aliases[i] + && zend_string_equals_ci(alias->trait_method.method_name, fnname) + ) { fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK)); - - /** Record the trait from which this alias was resolved. */ - if (!aliases[i]) { - aliases[i] = fn->common.scope; - } - if (!alias->trait_method.class_name) { - /* TODO: try to avoid this assignment (it's necessary only for reflection) */ - alias->trait_method.class_name = zend_string_copy(fn->common.scope->name); - } } alias_ptr++; alias = *alias_ptr; @@ -1862,9 +1843,11 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e aliases = ecalloc(i, sizeof(zend_class_entry*)); i = 0; while (ce->trait_aliases[i]) { - /** For all aliases with an explicit class name, resolve the class now. */ - if (ce->trait_aliases[i]->trait_method.class_name) { - cur_method_ref = &ce->trait_aliases[i]->trait_method; + zend_trait_alias *cur_alias = ce->trait_aliases[i]; + cur_method_ref = &ce->trait_aliases[i]->trait_method; + lcname = zend_string_tolower(cur_method_ref->method_name); + if (cur_method_ref->class_name) { + /* For all aliases with an explicit class name, resolve the class now. */ trait = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD); if (!trait) { zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name)); @@ -1872,13 +1855,47 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_e zend_check_trait_usage(ce, trait, traits); aliases[i] = trait; - /** And, ensure that the referenced method is resolvable, too. */ - lcname = zend_string_tolower(cur_method_ref->method_name); + /* And, ensure that the referenced method is resolvable, too. */ if (!zend_hash_exists(&trait->function_table, lcname)) { zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name)); } - zend_string_release_ex(lcname, 0); + } else { + /* Find out which trait this method refers to. */ + trait = NULL; + for (j = 0; j < ce->num_traits; j++) { + if (traits[j]) { + if (zend_hash_exists(&traits[j]->function_table, lcname)) { + if (!trait) { + trait = traits[j]; + continue; + } + + // TODO: This is ambiguous! The first trait is assumed. + break; + } + } + } + + /* Non-absolute method reference refers to method that does not exist. */ + if (!trait) { + if (cur_alias->alias) { + zend_error_noreturn(E_COMPILE_ERROR, + "An alias (%s) was defined for method %s(), but this method does not exist", + ZSTR_VAL(cur_alias->alias), + ZSTR_VAL(cur_alias->trait_method.method_name)); + } else { + zend_error_noreturn(E_COMPILE_ERROR, + "The modifiers of the trait method %s() are changed, but this method does not exist. Error", + ZSTR_VAL(cur_alias->trait_method.method_name)); + } + } + + aliases[i] = trait; + + /* TODO: try to avoid this assignment (it's necessary only for reflection) */ + cur_method_ref->class_name = zend_string_copy(trait->name); } + zend_string_release_ex(lcname, 0); i++; } } @@ -2066,56 +2083,6 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent } /* }}} */ -static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce, zend_class_entry **aliases) /* {{{ */ -{ - int i = 0; - zend_trait_alias* cur_alias; - zend_string* lc_method_name; - - if (ce->trait_aliases) { - while (ce->trait_aliases[i]) { - cur_alias = ce->trait_aliases[i]; - /** The trait for this alias has not been resolved, this means, this - alias was not applied. Abort with an error. */ - if (!aliases[i]) { - if (cur_alias->alias) { - /** Plain old inconsistency/typo/bug */ - zend_error_noreturn(E_COMPILE_ERROR, - "An alias (%s) was defined for method %s(), but this method does not exist", - ZSTR_VAL(cur_alias->alias), - ZSTR_VAL(cur_alias->trait_method.method_name)); - } else { - /** Here are two possible cases: - 1) this is an attempt to modify the visibility - of a method introduce as part of another alias. - Since that seems to violate the DRY principle, - we check against it and abort. - 2) it is just a plain old inconsitency/typo/bug - as in the case where alias is set. */ - - lc_method_name = zend_string_tolower( - cur_alias->trait_method.method_name); - if (zend_hash_exists(&ce->function_table, - lc_method_name)) { - zend_string_release_ex(lc_method_name, 0); - zend_error_noreturn(E_COMPILE_ERROR, - "The modifiers for the trait alias %s() need to be changed in the same statement in which the alias is defined. Error", - ZSTR_VAL(cur_alias->trait_method.method_name)); - } else { - zend_string_release_ex(lc_method_name, 0); - zend_error_noreturn(E_COMPILE_ERROR, - "The modifiers of the trait method %s() are changed, but this method does not exist. Error", - ZSTR_VAL(cur_alias->trait_method.method_name)); - - } - } - } - i++; - } - } -} -/* }}} */ - static void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */ { HashTable **exclude_tables; @@ -2153,9 +2120,6 @@ static void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */ /* first care about all methods to be flattened into the class */ zend_do_traits_method_binding(ce, traits, exclude_tables, aliases); - /* Aliases which have not been applied indicate typos/bugs. */ - zend_do_check_for_inconsistent_traits_aliasing(ce, aliases); - if (aliases) { efree(aliases); } |