From 1a19d3c06a637fbf38f35d9712056285f8b952f9 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Fri, 14 May 2021 10:02:05 -0400 Subject: [PATCH] Support doc comments on enum cases Because php supports doc comments on class constants, I believe it would also make sense to support them on enum cases. I don't have strong opinions about whether attributes should be moved to be the last element or whether the doc comment should go after the attribute, but the ast will likely change again before php 8.1 is stable. So far, all attributes are the last ast child node. I didn't notice that doc comments weren't implemented due to https://github.com/php/php-src/pull/6489 being a large change. https://wiki.php.net/rfc/enumerations did not mention whether or not doc comments were meant to be supported --- Zend/zend_ast.c | 8 +++---- Zend/zend_ast.h | 2 +- Zend/zend_compile.c | 12 ++++++++-- Zend/zend_language_parser.y | 4 ++-- .../ReflectionEnumUnitCase_getDocComment.phpt | 23 +++++++++++++++++++ 5 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 ext/reflection/tests/ReflectionEnumUnitCase_getDocComment.phpt diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index a09c13fd89ec..0d4a9dff5aaf 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -2201,8 +2201,8 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio zend_ast_export_name(str, ast->child[1], 0, indent); APPEND_DEFAULT_VALUE(2); case ZEND_AST_ENUM_CASE: - if (ast->child[2]) { - zend_ast_export_attributes(str, ast->child[2], indent, 1); + if (ast->child[3]) { + zend_ast_export_attributes(str, ast->child[3], indent, 1); } smart_str_appends(str, "case "); zend_ast_export_name(str, ast->child[0], 0, indent); @@ -2329,14 +2329,12 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr) ast->child[2] = attr; break; case ZEND_AST_PARAM: + case ZEND_AST_ENUM_CASE: ast->child[3] = attr; break; case ZEND_AST_CLASS_CONST_GROUP: ast->child[1] = attr; break; - case ZEND_AST_ENUM_CASE: - ast->child[2] = attr; - break; EMPTY_SWITCH_DEFAULT_CASE() } diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index fb6587b48cd3..0e3468ebde11 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -159,7 +159,6 @@ enum _zend_ast_kind { ZEND_AST_PROP_GROUP, ZEND_AST_PROP_ELEM, ZEND_AST_CONST_ELEM, - ZEND_AST_ENUM_CASE, // Pseudo node for initializing enums ZEND_AST_CONST_ENUM_INIT, @@ -167,6 +166,7 @@ enum _zend_ast_kind { /* 4 child nodes */ ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_FOREACH, + ZEND_AST_ENUM_CASE, /* 5 child nodes */ ZEND_AST_PARAM = 5 << ZEND_AST_NUM_CHILDREN_SHIFT, diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 1a884206fd7c..ee01dee43f47 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7748,11 +7748,19 @@ static void zend_compile_enum_case(zend_ast *ast) zval value_zv; zend_const_expr_to_zval(&value_zv, &const_enum_init_ast); - zend_class_constant *c = zend_declare_class_constant_ex(enum_class, enum_case_name, &value_zv, ZEND_ACC_PUBLIC, NULL); + + /* Doc comment has been appended as second last element in ZEND_AST_ENUM ast - attributes are conventionally last */ + zend_ast *doc_comment_ast = ast->child[2]; + zend_string *doc_comment = NULL; + if (doc_comment_ast) { + doc_comment = zend_string_copy(zend_ast_get_str(doc_comment_ast)); + } + + zend_class_constant *c = zend_declare_class_constant_ex(enum_class, enum_case_name, &value_zv, ZEND_ACC_PUBLIC, doc_comment); ZEND_CLASS_CONST_FLAGS(c) |= ZEND_CLASS_CONST_IS_CASE; zend_ast_destroy(const_enum_init_ast); - zend_ast *attr_ast = ast->child[2]; + zend_ast *attr_ast = ast->child[3]; if (attr_ast) { zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST); } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index fcbdcb622261..917a34b8c3c2 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -607,8 +607,8 @@ enum_backing_type: ; enum_case: - T_CASE identifier enum_case_expr ';' - { $$ = zend_ast_create(ZEND_AST_ENUM_CASE, $2, $3, NULL); } + T_CASE backup_doc_comment identifier enum_case_expr ';' + { $$ = zend_ast_create(ZEND_AST_ENUM_CASE, $3, $4, ($2 ? zend_ast_create_zval_from_str($2) : NULL), NULL); } ; enum_case_expr: diff --git a/ext/reflection/tests/ReflectionEnumUnitCase_getDocComment.phpt b/ext/reflection/tests/ReflectionEnumUnitCase_getDocComment.phpt new file mode 100644 index 000000000000..d51543601d91 --- /dev/null +++ b/ext/reflection/tests/ReflectionEnumUnitCase_getDocComment.phpt @@ -0,0 +1,23 @@ +--TEST-- +ReflectionEnumUnitCase::getDocComment() +--FILE-- +getDocComment()); +var_dump((new ReflectionEnumUnitCase(Foo::class, 'Baz'))->getDocComment()); +var_dump((new ReflectionClassConstant(Foo::class, 'Bar'))->getDocComment()); +var_dump((new ReflectionClassConstant(Foo::class, 'Baz'))->getDocComment()); + +?> +--EXPECT-- +string(26) "/** Example doc comment */" +bool(false) +string(26) "/** Example doc comment */" +bool(false)