@@ -253,6 +253,7 @@ static const ast_flag_info flag_info[] = {
253
253
{ ZEND_AST_FUNC_DECL , 1 , func_flags },
254
254
{ ZEND_AST_CLOSURE , 1 , func_flags },
255
255
{ ZEND_AST_PROP_DECL , 1 , modifier_flags },
256
+ { ZEND_AST_PROP_GROUP , 1 , modifier_flags },
256
257
{ ZEND_AST_CLASS_CONST_DECL , 1 , visibility_flags },
257
258
{ ZEND_AST_TRAIT_ALIAS , 1 , modifier_flags },
258
259
};
@@ -311,6 +312,9 @@ static inline zend_bool ast_kind_uses_attr(zend_ast_kind kind) {
311
312
|| kind == ZEND_AST_UNARY_OP || kind == ZEND_AST_BINARY_OP || kind == ZEND_AST_ASSIGN_OP
312
313
|| kind == ZEND_AST_CAST || kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_ARRAY_ELEM
313
314
|| kind == ZEND_AST_INCLUDE_OR_EVAL || kind == ZEND_AST_USE || kind == ZEND_AST_PROP_DECL
315
+ #if PHP_VERSION_ID >= 70400
316
+ || kind == ZEND_AST_PROP_GROUP
317
+ #endif
314
318
|| kind == ZEND_AST_GROUP_USE || kind == ZEND_AST_USE_ELEM
315
319
|| kind == AST_NAME || kind == AST_CLOSURE_VAR || kind == ZEND_AST_CLASS_CONST_DECL
316
320
|| kind == ZEND_AST_ARRAY ;
@@ -336,6 +340,9 @@ static inline zend_bool ast_is_name(zend_ast *ast, zend_ast *parent, uint32_t i)
336
340
|| parent -> kind == ZEND_AST_CALL || parent -> kind == ZEND_AST_CONST
337
341
|| parent -> kind == ZEND_AST_NEW || parent -> kind == ZEND_AST_STATIC_CALL
338
342
|| parent -> kind == ZEND_AST_CLASS_CONST || parent -> kind == ZEND_AST_STATIC_PROP
343
+ #if PHP_VERSION_ID >= 70400
344
+ || parent -> kind == ZEND_AST_PROP_GROUP
345
+ #endif
339
346
;
340
347
}
341
348
@@ -354,7 +361,11 @@ static inline zend_bool ast_is_name(zend_ast *ast, zend_ast *parent, uint32_t i)
354
361
/* Assumes that ast_is_name is already true */
355
362
static inline zend_bool ast_is_type (zend_ast * ast , zend_ast * parent , uint32_t i ) {
356
363
if (i == 0 ) {
357
- return parent -> kind == ZEND_AST_PARAM ;
364
+ return parent -> kind == ZEND_AST_PARAM
365
+ #if PHP_VERSION_ID >= 70400
366
+ || parent -> kind == ZEND_AST_PROP_GROUP
367
+ #endif
368
+ ;
358
369
}
359
370
if (i == 3 ) {
360
371
return parent -> kind == ZEND_AST_CLOSURE || parent -> kind == ZEND_AST_FUNC_DECL
@@ -512,6 +523,46 @@ static void ast_create_virtual_node(
512
523
zv , kind , attr , zend_ast_get_lineno (child ), state , 1 , & child_zv );
513
524
}
514
525
526
+ static inline void ast_name_to_zval (zend_ast * child , zend_ast * ast , zval * child_zv , int i , ast_state_info_t * state ) {
527
+ zend_uchar type ;
528
+ zend_bool is_nullable = 0 ;
529
+ if (child -> attr & ZEND_TYPE_NULLABLE ) {
530
+ is_nullable = 1 ;
531
+ child -> attr &= ~ZEND_TYPE_NULLABLE ;
532
+ }
533
+
534
+ if (child -> attr == ZEND_NAME_FQ ) {
535
+ /* Ensure there is no leading \ for fully-qualified names. This can happen if
536
+ * something like ('\bar')() is used. */
537
+ zval * name = zend_ast_get_zval (child );
538
+ if (Z_STRVAL_P (name )[0 ] == '\\' ) {
539
+ zend_string * new_name = zend_string_init (
540
+ Z_STRVAL_P (name ) + 1 , Z_STRLEN_P (name ) - 1 , 0 );
541
+ zend_string_release (Z_STR_P (name ));
542
+ Z_STR_P (name ) = new_name ;
543
+ }
544
+ }
545
+
546
+ if (child -> attr == ZEND_NAME_NOT_FQ
547
+ && ast_is_type (child , ast , i )
548
+ && (type = lookup_builtin_type (zend_ast_get_str (child )))
549
+ ) {
550
+ /* Convert "int" etc typehints to TYPE nodes */
551
+ ast_create_virtual_node_ex (
552
+ child_zv , ZEND_AST_TYPE , type , zend_ast_get_lineno (child ), state , 0 );
553
+ } else {
554
+ ast_create_virtual_node (child_zv , AST_NAME , child -> attr , child , state );
555
+ }
556
+
557
+ if (is_nullable ) {
558
+ /* Create explicit AST_NULLABLE_TYPE node */
559
+ zval tmp ;
560
+ ZVAL_COPY_VALUE (& tmp , child_zv );
561
+ ast_create_virtual_node_ex (
562
+ child_zv , AST_NULLABLE_TYPE , 0 , zend_ast_get_lineno (child ), state , 1 , & tmp );
563
+ }
564
+ }
565
+
515
566
static void ast_fill_children_ht (HashTable * ht , zend_ast * ast , ast_state_info_t * state ) {
516
567
uint32_t i , count ;
517
568
zend_bool is_list = zend_ast_is_list (ast );
@@ -542,43 +593,7 @@ static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, ast_state_info_t
542
593
} else
543
594
#endif
544
595
if (ast_is_name (child , ast , i )) {
545
- zend_uchar type ;
546
- zend_bool is_nullable = 0 ;
547
- if (child -> attr & ZEND_TYPE_NULLABLE ) {
548
- is_nullable = 1 ;
549
- child -> attr &= ~ZEND_TYPE_NULLABLE ;
550
- }
551
-
552
- if (child -> attr == ZEND_NAME_FQ ) {
553
- /* Ensure there is no leading \ for fully-qualified names. This can happen if
554
- * something like ('\bar')() is used. */
555
- zval * name = zend_ast_get_zval (child );
556
- if (Z_STRVAL_P (name )[0 ] == '\\' ) {
557
- zend_string * new_name = zend_string_init (
558
- Z_STRVAL_P (name ) + 1 , Z_STRLEN_P (name ) - 1 , 0 );
559
- zend_string_release (Z_STR_P (name ));
560
- Z_STR_P (name ) = new_name ;
561
- }
562
- }
563
-
564
- if (child -> attr == ZEND_NAME_NOT_FQ
565
- && ast_is_type (child , ast , i )
566
- && (type = lookup_builtin_type (zend_ast_get_str (child )))
567
- ) {
568
- /* Convert "int" etc typehints to TYPE nodes */
569
- ast_create_virtual_node_ex (
570
- & child_zv , ZEND_AST_TYPE , type , zend_ast_get_lineno (child ), state , 0 );
571
- } else {
572
- ast_create_virtual_node (& child_zv , AST_NAME , child -> attr , child , state );
573
- }
574
-
575
- if (is_nullable ) {
576
- /* Create explicit AST_NULLABLE_TYPE node */
577
- zval tmp ;
578
- ZVAL_COPY_VALUE (& tmp , & child_zv );
579
- ast_create_virtual_node_ex (
580
- & child_zv , AST_NULLABLE_TYPE , 0 , zend_ast_get_lineno (child ), state , 1 , & tmp );
581
- }
596
+ ast_name_to_zval (child , ast , & child_zv , i , state );
582
597
} else if (child && child -> kind == ZEND_AST_TYPE && (child -> attr & ZEND_TYPE_NULLABLE )) {
583
598
child -> attr &= ~ZEND_TYPE_NULLABLE ;
584
599
ast_create_virtual_node (& child_zv , AST_NULLABLE_TYPE , 0 , child , state );
@@ -693,6 +708,19 @@ static void ast_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state) {
693
708
ast -> kind = ZEND_AST_UNARY_OP ;
694
709
ast -> attr = AST_MINUS ;
695
710
break ;
711
+ #if PHP_VERSION_ID >= 70400
712
+ case ZEND_AST_PROP_GROUP :
713
+ if (state -> version < 70 ) {
714
+ // In versions less than 70, just omit property type information entirely.
715
+ // ast->child is [type_ast, prop_ast]
716
+ ast_to_zval (zv , ast -> child [1 ], state );
717
+ // The property visibility is on the AST_PROP_GROUP node.
718
+ // Add it to the AST_PROP_DECL node for old
719
+ ast_update_property_long (zv , AST_STR (str_flags ), ast -> attr , AST_CACHE_SLOT_FLAGS );
720
+ return ;
721
+ }
722
+ break ;
723
+ #endif
696
724
}
697
725
698
726
#if PHP_VERSION_ID < 70100
@@ -747,9 +775,20 @@ static void ast_to_zval(zval *zv, zend_ast *ast, ast_state_info_t *state) {
747
775
}
748
776
749
777
ast_fill_children_ht (Z_ARRVAL (children_zv ), ast , state );
778
+ #if PHP_VERSION_ID < 70400
779
+ if (ast -> kind == ZEND_AST_PROP_DECL && state -> version >= 70 ) {
780
+ zval type_zval ;
781
+ zval prop_group_zval = * zv ;
782
+ ZVAL_NULL (& type_zval );
783
+ // For version 70, create an AST_PROP_GROUP wrapping the created AST_PROP_DECL.
784
+ ast_create_virtual_node_ex (
785
+ zv , ZEND_AST_PROP_GROUP , ast -> attr , zend_ast_get_lineno (ast ), state , 2 , & type_zval , & prop_group_zval );
786
+ ast_update_property_long (& prop_group_zval , AST_STR (str_flags ), 0 , AST_CACHE_SLOT_FLAGS );
787
+ }
788
+ #endif
750
789
}
751
790
752
- static const zend_long versions [] = {50 , 60 };
791
+ static const zend_long versions [] = {50 , 60 , 70 };
753
792
static const size_t versions_count = sizeof (versions )/sizeof (versions [0 ]);
754
793
755
794
static inline zend_bool ast_version_deprecated (zend_long version ) {
0 commit comments