| 3929 | /* ── entry: cbm_run_php_lsp ─────────────────────────────────────── */ |
| 3930 | |
| 3931 | void cbm_run_php_lsp(CBMArena *arena, CBMFileResult *result, const char *source, int source_len, |
| 3932 | TSNode root) { |
| 3933 | if (!result || !arena || ts_node_is_null(root)) |
| 3934 | return; |
| 3935 | |
| 3936 | CBMTypeRegistry reg; |
| 3937 | cbm_registry_init(®, arena); |
| 3938 | |
| 3939 | /* Phase A: register stdlib types/functions. */ |
| 3940 | cbm_php_stdlib_register(®, arena); |
| 3941 | |
| 3942 | const char *module_qn = result->module_qn; |
| 3943 | |
| 3944 | /* Phase B: register types and methods/functions from this file's defs. |
| 3945 | * We do not yet know the namespace mapping for the type's QN, so we |
| 3946 | * trust the QN that the unified extractor already produced. */ |
| 3947 | for (int i = 0; i < result->defs.count; i++) { |
| 3948 | CBMDefinition *d = &result->defs.items[i]; |
| 3949 | if (!d->qualified_name || !d->name || !d->label) |
| 3950 | continue; |
| 3951 | |
| 3952 | if (strcmp(d->label, "Class") == 0 || strcmp(d->label, "Interface") == 0 || |
| 3953 | strcmp(d->label, "Trait") == 0 || strcmp(d->label, "Enum") == 0 || |
| 3954 | strcmp(d->label, "Type") == 0) { |
| 3955 | CBMRegisteredType rt; |
| 3956 | memset(&rt, 0, sizeof(rt)); |
| 3957 | rt.qualified_name = d->qualified_name; |
| 3958 | rt.short_name = d->name; |
| 3959 | rt.is_interface = (strcmp(d->label, "Interface") == 0); |
| 3960 | |
| 3961 | /* Hoist base_classes as embedded_types so php_lookup_method's |
| 3962 | * parent walk works. */ |
| 3963 | if (d->base_classes) { |
| 3964 | int bc = 0; |
| 3965 | while (d->base_classes[bc]) |
| 3966 | bc++; |
| 3967 | if (bc > 0) { |
| 3968 | const char **emb = (const char **)cbm_arena_alloc( |
| 3969 | arena, (size_t)(bc + 1) * sizeof(const char *)); |
| 3970 | if (emb) { |
| 3971 | for (int j = 0; j < bc; j++) { |
| 3972 | const char *base = d->base_classes[j]; |
| 3973 | /* Try same-module, then bare. */ |
| 3974 | const char *qualified = base; |
| 3975 | if (base[0] != '\\' && !strchr(base, '.')) { |
| 3976 | qualified = cbm_arena_sprintf(arena, "%s.%s", module_qn, base); |
| 3977 | } else if (base[0] == '\\') { |
| 3978 | qualified = php_ns_to_dot(arena, base + 1); |
| 3979 | } else { |
| 3980 | qualified = php_ns_to_dot(arena, base); |
| 3981 | } |
| 3982 | emb[j] = qualified; |
| 3983 | } |
| 3984 | emb[bc] = NULL; |
| 3985 | rt.embedded_types = emb; |
| 3986 | } |
| 3987 | } |
| 3988 | } |
no test coverage detected