Skip to content

Changes Requested in Review #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions Zend/tests/attributes/001_placement.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ Attributes can be placed on all supported elements.
class Foo
{
<<A1(2)>>
public const FOO = 'foo', BAR = 'bar';
public const FOO = 'foo';

<<A1(3)>>
public $x, $y;
public $x;

<<A1(4)>>
public function foo(<<A1(5)>> $a, <<A1(6)>> $b) { }
Expand All @@ -30,9 +30,7 @@ $ref = new \ReflectionClass(Foo::class);
$sources = [
$ref,
$ref->getReflectionConstant('FOO'),
$ref->getReflectionConstant('BAR'),
$ref->getProperty('x'),
$ref->getProperty('y'),
$ref->getMethod('foo'),
$ref->getMethod('foo')->getParameters()[0],
$ref->getMethod('foo')->getParameters()[1],
Expand Down Expand Up @@ -71,9 +69,6 @@ array(1) {
int(2)
}

string(23) "ReflectionClassConstant"
int(0)

string(18) "ReflectionProperty"
int(1)
string(2) "A1"
Expand All @@ -82,9 +77,6 @@ array(1) {
int(3)
}

string(18) "ReflectionProperty"
int(0)

string(16) "ReflectionMethod"
int(1)
string(2) "A1"
Expand Down
112 changes: 112 additions & 0 deletions Zend/tests/attributes/013_scope_resolution.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
--TEST--
Attributes make use of correct scope.
--FILE--
<?php

<<A1(self::class, self::FOO)>>
class C1
{
<<A1(self::class, self::FOO)>>
private const FOO = 'foo';

<<A1(self::class, self::FOO)>>
public $a;

<<A1(self::class, self::FOO)>>
public function bar(<<A1(self::class, self::FOO)>> $p) { }
}

$ref = new \ReflectionClass(C1::class);
print_r($ref->getAttributes()[0]->getArguments());
print_r($ref->getReflectionConstant('FOO')->getAttributes()[0]->getArguments());
print_r($ref->getProperty('a')->getAttributes()[0]->getArguments());
print_r($ref->getMethod('bar')->getAttributes()[0]->getArguments());
print_r($ref->getMethod('bar')->getParameters()[0]->getAttributes()[0]->getArguments());

echo "\n";

class C2
{
private const FOO = 'foo';

public static function foo()
{
return <<A1(self::class, self::FOO)>> function (<<A1(self::class, self::FOO)>> $p) { };
}
}

$ref = new \ReflectionFunction(C2::foo());
print_r($ref->getAttributes()[0]->getArguments());
print_r($ref->getParameters()[0]->getAttributes()[0]->getArguments());

echo "\n";

class C3
{
private const FOO = 'foo';

public static function foo()
{
return new <<A1(self::class, self::FOO)>> class() {
private const FOO = 'bar';

<<A1(self::class, self::FOO)>>
public function bar() { }
};
}
}

$obj = C3::foo();
$ref = new \ReflectionObject($obj);
$name = $ref->getMethod('bar')->getAttributes()[0]->getArguments()[0];

print_r($ref->getAttributes()[0]->getArguments());
var_dump($name == get_class($obj));
var_dump($ref->getMethod('bar')->getAttributes()[0]->getArguments()[1]);

?>
--EXPECT--
Array
(
[0] => C1
[1] => foo
)
Array
(
[0] => C1
[1] => foo
)
Array
(
[0] => C1
[1] => foo
)
Array
(
[0] => C1
[1] => foo
)
Array
(
[0] => C1
[1] => foo
)

Array
(
[0] => C2
[1] => foo
)
Array
(
[0] => C2
[1] => foo
)

Array
(
[0] => C3
[1] => foo
)
bool(true)
string(3) "bar"
14 changes: 14 additions & 0 deletions Zend/tests/attributes/014_class_const_group.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Attributes cannot be applied to groups of class constants.
--FILE--
<?php

class C1
{
<<A1>>
public const A = 1, B = 2;
}

?>
--EXPECTF--
Fatal error: Cannot apply attributes to a group of constants in %s
14 changes: 14 additions & 0 deletions Zend/tests/attributes/015_property_group.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Attributes cannot be applied to groups of properties.
--FILE--
<?php

class C1
{
<<A1>>
public $x, $y;
}

?>
--EXPECTF--
Fatal error: Cannot apply attributes to a group of properties in %s
4 changes: 2 additions & 2 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1590,7 +1590,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_AST_CLASS_CONST_DECL:
smart_str_appends(str, "const ");
goto simple_list;
case ZEND_AST_CLASS_CONST_DECL_ATTRIBUTES:
case ZEND_AST_CLASS_CONST_GROUP:
if (ast->child[1]) {
zend_ast_export_attributes(str, ast->child[1], indent, 1);
}
Expand Down Expand Up @@ -2192,7 +2192,7 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
case ZEND_AST_PARAM:
ast->child[3] = attr;
break;
case ZEND_AST_CLASS_CONST_DECL_ATTRIBUTES:
case ZEND_AST_CLASS_CONST_GROUP:
ast->child[1] = attr;
break;
EMPTY_SWITCH_DEFAULT_CASE()
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ enum _zend_ast_kind {
ZEND_AST_USE_ELEM,
ZEND_AST_TRAIT_ALIAS,
ZEND_AST_GROUP_USE,
ZEND_AST_CLASS_CONST_DECL_ATTRIBUTES,
ZEND_AST_CLASS_CONST_GROUP,
ZEND_AST_ATTRIBUTE,

/* 3 child nodes */
Expand Down
24 changes: 22 additions & 2 deletions Zend/zend_attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ ZEND_API void zend_attribute_free(zend_attribute *attr)
efree(attr);
}

ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
{
if (attributes) {
zend_attribute *attr;
Expand All @@ -53,7 +53,7 @@ ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *
return NULL;
}

ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
{
if (attributes) {
zend_attribute *attr;
Expand All @@ -70,6 +70,26 @@ ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const cha
return NULL;
}

ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname)
{
return get_attribute(attributes, lcname, 0);
}

ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len)
{
return get_attribute_str(attributes, str, len, 0);
}

ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
{
return get_attribute(attributes, lcname, offset + 1);
}

ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
{
return get_attribute_str(attributes, str, len, offset + 1);
}

ZEND_API void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator)
{
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
Expand Down
8 changes: 6 additions & 2 deletions Zend/zend_attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extern ZEND_API zend_class_entry *zend_ce_php_compiler_attribute;
typedef struct _zend_attribute {
zend_string *name;
zend_string *lcname;
/* Parameter offsets start at 1, everything else uses 0. */
uint32_t offset;
uint32_t argc;
zval argv[1];
Expand All @@ -28,8 +29,11 @@ typedef void (*zend_attributes_internal_validator)(zend_attribute *attr, int tar

ZEND_API void zend_attribute_free(zend_attribute *attr);

ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset);
ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset);
ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname);
ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len);

ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset);
ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset);

ZEND_API void zend_compiler_attribute_register(zend_class_entry *ce, zend_attributes_internal_validator validator);
ZEND_API zend_attributes_internal_validator zend_attribute_get_validator(zend_string *lcname);
Expand Down
18 changes: 12 additions & 6 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -2367,7 +2367,7 @@ static inline zend_bool zend_is_variable_or_call(zend_ast *ast) /* {{{ */
static inline zend_bool zend_is_unticked_stmt(zend_ast *ast) /* {{{ */
{
return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL
|| ast->kind == ZEND_AST_PROP_DECL || ast->kind == ZEND_AST_CLASS_CONST_DECL_ATTRIBUTES
|| ast->kind == ZEND_AST_PROP_DECL || ast->kind == ZEND_AST_CLASS_CONST_GROUP
|| ast->kind == ZEND_AST_USE_TRAIT || ast->kind == ZEND_AST_METHOD;
}
/* }}} */
Expand Down Expand Up @@ -6520,8 +6520,6 @@ void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, H
}

zend_declare_typed_property(ce, name, &value_zv, flags, doc_comment, attributes, type);

attributes = NULL;
}
}
/* }}} */
Expand All @@ -6534,6 +6532,11 @@ void zend_compile_prop_group(zend_ast *list) /* {{{ */
zend_ast *prop_ast = list->child[1];

if (list->child[2]) {
if (zend_ast_get_list(prop_ast)->children > 1) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot apply attributes to a group of properties");
return;
}

attributes = create_attribute_array();
zend_compile_attributes(attributes, list->child[2], 0, ZEND_ATTRIBUTE_TARGET_PROPERTY);
}
Expand Down Expand Up @@ -6567,6 +6570,11 @@ void zend_compile_class_const_decl(zend_ast *ast, zend_ast *attr_ast) /* {{{ */
}

if (attr_ast) {
if (list->children > 1) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot apply attributes to a group of constants");
return;
}

attributes = create_attribute_array();
zend_compile_attributes(attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
}
Expand All @@ -6586,8 +6594,6 @@ void zend_compile_class_const_decl(zend_ast *ast, zend_ast *attr_ast) /* {{{ */

zend_const_expr_to_zval(&value_zv, value_ast);
zend_declare_class_constant_ex(ce, name, &value_zv, ast->attr, doc_comment, attributes);

attributes = NULL;
}
}
/* }}} */
Expand Down Expand Up @@ -8885,7 +8891,7 @@ void zend_compile_stmt(zend_ast *ast) /* {{{ */
case ZEND_AST_PROP_GROUP:
zend_compile_prop_group(ast);
break;
case ZEND_AST_CLASS_CONST_DECL_ATTRIBUTES:
case ZEND_AST_CLASS_CONST_GROUP:
zend_compile_class_const_decl(ast->child[0], ast->child[1]);
break;
case ZEND_AST_USE_TRAIT:
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ annotated_class_statement:
{ $$ = zend_ast_create(ZEND_AST_PROP_GROUP, $2, $3, NULL);
$$->attr = $1; }
| method_modifiers T_CONST class_const_list ';'
{ $$ = zend_ast_create(ZEND_AST_CLASS_CONST_DECL_ATTRIBUTES, $3, NULL); $3->attr = $1; }
{ $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $3, NULL); $3->attr = $1; }
| method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')'
return_type backup_fn_flags method_body backup_fn_flags
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1 | $12, $2, $5,
Expand Down
2 changes: 1 addition & 1 deletion ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -6582,7 +6582,7 @@ ZEND_METHOD(ReflectionAttribute, newInstance)
RETURN_THROWS();
}

if (ce->type == ZEND_USER_CLASS && !zend_get_attribute_str(ce->info.user.attributes, ZEND_STRL("phpattribute"), 0)) {
if (ce->type == ZEND_USER_CLASS && !zend_get_attribute_str(ce->info.user.attributes, ZEND_STRL("phpattribute"))) {
zend_throw_error(NULL, "Attempting to use class '%s' as attribute that does not have <<PhpAttribute>>.", ZSTR_VAL(attr->data->name));
RETURN_THROWS();
} else if (ce->type == ZEND_INTERNAL_CLASS && !zend_attribute_get_validator(attr->data->lcname)) {
Expand Down