| 3103 | } |
| 3104 | |
| 3105 | static void extract_property_decl(PHPLSPContext *ctx, TSNode prop_decl, php_class_fields_t *out) { |
| 3106 | TSNode tnode = ts_node_child_by_field_name(prop_decl, "type", 4); |
| 3107 | const CBMType *ptype = NULL; |
| 3108 | if (!ts_node_is_null(tnode)) |
| 3109 | ptype = php_parse_type_node(ctx, tnode); |
| 3110 | if (!ptype || ptype->kind == CBM_TYPE_UNKNOWN) { |
| 3111 | /* Tree-sitter-php may put the type as a named child without field. */ |
| 3112 | uint32_t nc = ts_node_child_count(prop_decl); |
| 3113 | for (uint32_t i = 0; i < nc; i++) { |
| 3114 | TSNode c = ts_node_child(prop_decl, i); |
| 3115 | if (ts_node_is_null(c) || !ts_node_is_named(c)) |
| 3116 | continue; |
| 3117 | const char *k = ts_node_type(c); |
| 3118 | if (strcmp(k, "named_type") == 0 || strcmp(k, "primitive_type") == 0 || |
| 3119 | strcmp(k, "union_type") == 0 || strcmp(k, "intersection_type") == 0 || |
| 3120 | strcmp(k, "optional_type") == 0) { |
| 3121 | ptype = php_parse_type_node(ctx, c); |
| 3122 | break; |
| 3123 | } |
| 3124 | } |
| 3125 | } |
| 3126 | if (!ptype || ptype->kind == CBM_TYPE_UNKNOWN) |
| 3127 | return; |
| 3128 | |
| 3129 | /* Find the property_element children (each has variable_name + maybe default). */ |
| 3130 | uint32_t nc = ts_node_child_count(prop_decl); |
| 3131 | for (uint32_t i = 0; i < nc; i++) { |
| 3132 | TSNode c = ts_node_child(prop_decl, i); |
| 3133 | if (ts_node_is_null(c) || !ts_node_is_named(c)) |
| 3134 | continue; |
| 3135 | const char *k = ts_node_type(c); |
| 3136 | if (strcmp(k, "property_element") == 0) { |
| 3137 | uint32_t bnc = ts_node_child_count(c); |
| 3138 | for (uint32_t j = 0; j < bnc; j++) { |
| 3139 | TSNode b = ts_node_child(c, j); |
| 3140 | if (!ts_node_is_null(b) && ts_node_is_named(b) && |
| 3141 | strcmp(ts_node_type(b), "variable_name") == 0) { |
| 3142 | char *vt = php_node_text(ctx, b); |
| 3143 | if (!vt) |
| 3144 | continue; |
| 3145 | const char *name = (vt[0] == '$') ? vt + 1 : vt; |
| 3146 | add_field(out, ctx->arena, name, ptype); |
| 3147 | break; |
| 3148 | } |
| 3149 | } |
| 3150 | } else if (strcmp(k, "variable_name") == 0) { |
| 3151 | char *vt = php_node_text(ctx, c); |
| 3152 | if (vt) { |
| 3153 | const char *name = (vt[0] == '$') ? vt + 1 : vt; |
| 3154 | add_field(out, ctx->arena, name, ptype); |
| 3155 | } |
| 3156 | } |
| 3157 | } |
| 3158 | } |
| 3159 | |
| 3160 | static void extract_promoted_param(PHPLSPContext *ctx, TSNode param, php_class_fields_t *out) { |
| 3161 | /* property_promotion_parameter has: visibility/readonly modifiers, |
no test coverage detected