| 2881 | } |
| 2882 | |
| 2883 | static void extract_property_decl(PHPLSPContext *ctx, TSNode prop_decl, php_class_fields_t *out) { |
| 2884 | TSNode tnode = ts_node_child_by_field_name(prop_decl, "type", 4); |
| 2885 | const CBMType *ptype = NULL; |
| 2886 | if (!ts_node_is_null(tnode)) |
| 2887 | ptype = php_parse_type_node(ctx, tnode); |
| 2888 | if (!ptype || ptype->kind == CBM_TYPE_UNKNOWN) { |
| 2889 | /* Tree-sitter-php may put the type as a named child without field. */ |
| 2890 | uint32_t nc = ts_node_child_count(prop_decl); |
| 2891 | for (uint32_t i = 0; i < nc; i++) { |
| 2892 | TSNode c = ts_node_child(prop_decl, i); |
| 2893 | if (ts_node_is_null(c) || !ts_node_is_named(c)) |
| 2894 | continue; |
| 2895 | const char *k = ts_node_type(c); |
| 2896 | if (strcmp(k, "named_type") == 0 || strcmp(k, "primitive_type") == 0 || |
| 2897 | strcmp(k, "union_type") == 0 || strcmp(k, "intersection_type") == 0 || |
| 2898 | strcmp(k, "optional_type") == 0) { |
| 2899 | ptype = php_parse_type_node(ctx, c); |
| 2900 | break; |
| 2901 | } |
| 2902 | } |
| 2903 | } |
| 2904 | if (!ptype || ptype->kind == CBM_TYPE_UNKNOWN) |
| 2905 | return; |
| 2906 | |
| 2907 | /* Find the property_element children (each has variable_name + maybe default). */ |
| 2908 | uint32_t nc = ts_node_child_count(prop_decl); |
| 2909 | for (uint32_t i = 0; i < nc; i++) { |
| 2910 | TSNode c = ts_node_child(prop_decl, i); |
| 2911 | if (ts_node_is_null(c) || !ts_node_is_named(c)) |
| 2912 | continue; |
| 2913 | const char *k = ts_node_type(c); |
| 2914 | if (strcmp(k, "property_element") == 0) { |
| 2915 | uint32_t bnc = ts_node_child_count(c); |
| 2916 | for (uint32_t j = 0; j < bnc; j++) { |
| 2917 | TSNode b = ts_node_child(c, j); |
| 2918 | if (!ts_node_is_null(b) && ts_node_is_named(b) && |
| 2919 | strcmp(ts_node_type(b), "variable_name") == 0) { |
| 2920 | char *vt = php_node_text(ctx, b); |
| 2921 | if (!vt) |
| 2922 | continue; |
| 2923 | const char *name = (vt[0] == '$') ? vt + 1 : vt; |
| 2924 | add_field(out, ctx->arena, name, ptype); |
| 2925 | break; |
| 2926 | } |
| 2927 | } |
| 2928 | } else if (strcmp(k, "variable_name") == 0) { |
| 2929 | char *vt = php_node_text(ctx, c); |
| 2930 | if (vt) { |
| 2931 | const char *name = (vt[0] == '$') ? vt + 1 : vt; |
| 2932 | add_field(out, ctx->arena, name, ptype); |
| 2933 | } |
| 2934 | } |
| 2935 | } |
| 2936 | } |
| 2937 | |
| 2938 | static void extract_promoted_param(PHPLSPContext *ctx, TSNode param, php_class_fields_t *out) { |
| 2939 | /* property_promotion_parameter has: visibility/readonly modifiers, |
no test coverage detected