| 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, |
| 3162 | * type, variable_name. */ |
| 3163 | TSNode tnode = ts_node_child_by_field_name(param, "type", 4); |
| 3164 | const CBMType *ptype = NULL; |
| 3165 | if (!ts_node_is_null(tnode)) |
| 3166 | ptype = php_parse_type_node(ctx, tnode); |
| 3167 | if (!ptype || ptype->kind == CBM_TYPE_UNKNOWN) { |
| 3168 | uint32_t nc = ts_node_child_count(param); |
| 3169 | for (uint32_t i = 0; i < nc; i++) { |
| 3170 | TSNode c = ts_node_child(param, i); |
| 3171 | if (ts_node_is_null(c) || !ts_node_is_named(c)) |
| 3172 | continue; |
| 3173 | const char *k = ts_node_type(c); |
| 3174 | if (strcmp(k, "named_type") == 0 || strcmp(k, "primitive_type") == 0 || |
| 3175 | strcmp(k, "union_type") == 0 || strcmp(k, "intersection_type") == 0 || |
| 3176 | strcmp(k, "optional_type") == 0) { |
| 3177 | ptype = php_parse_type_node(ctx, c); |
| 3178 | break; |
| 3179 | } |
| 3180 | } |
| 3181 | } |
| 3182 | if (!ptype || ptype->kind == CBM_TYPE_UNKNOWN) |
| 3183 | return; |
| 3184 | TSNode vname = ts_node_child_by_field_name(param, "name", 4); |
| 3185 | if (ts_node_is_null(vname)) { |
| 3186 | uint32_t nc = ts_node_child_count(param); |
| 3187 | for (uint32_t i = 0; i < nc; i++) { |
| 3188 | TSNode c = ts_node_child(param, i); |
| 3189 | if (!ts_node_is_null(c) && strcmp(ts_node_type(c), "variable_name") == 0) { |
| 3190 | vname = c; |
| 3191 | break; |
| 3192 | } |
| 3193 | } |
| 3194 | } |
| 3195 | if (ts_node_is_null(vname)) |
| 3196 | return; |
| 3197 | char *vt = php_node_text(ctx, vname); |
| 3198 | if (!vt) |
| 3199 | return; |
| 3200 | const char *n = (vt[0] == '$') ? vt + 1 : vt; |
| 3201 | add_field(out, ctx->arena, n, ptype); |
| 3202 | } |
| 3203 | |
| 3204 | /* Look at __construct: any `$this->X = $param;` where $param is a typed |
| 3205 | * parameter contributes a field type for X. */ |
no test coverage detected