From d60bc0e2d91d299c6cb03cb48672479bcffd03a7 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Fri, 14 May 2021 15:25:03 -0400 Subject: [PATCH] Support doc comments on enum cases (#6984) 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 a09c13fd89e..0d4a9dff5aa 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -2201,8 +2201,8 @@ simple_list: 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 fb6587b48cd..0e3468ebde1 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 6a16700d2c6..fbb680be2f7 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 fcbdcb62226..917a34b8c3c 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 00000000000..d51543601d9 --- /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)