@@ -568,6 +568,62 @@ TEST(phplsp_trait_self_use_terminates) {
568568 PASS ();
569569}
570570
571+ /* ── 23c. Regression #765: trait name collides with an aliased import ──
572+ *
573+ * `use Vendor\Pkg\Auditable as AuditableBase;` + `trait Auditable { use
574+ * AuditableBase; ... }` — the composed alias canonicalizes (via short-name
575+ * fallback) onto the ENCLOSING trait itself, which is the same
576+ * self-flattening loop as 23b arriving through the import alias: each
577+ * copied method re-matched the flatten filter while the registry grew,
578+ * OOM-ing the indexer (reported at 40+ GB). Guarded by the #920 pair
579+ * (self-flatten short-circuit + snapshotted loop bound); this fixture is
580+ * the exact reproducer from issue #765 and hung/OOM'd before those. */
581+ TEST (phplsp_trait_aliased_import_name_collision_terminates ) {
582+ const char * src = "<?php\n"
583+ "namespace App\\Demo;\n"
584+ "\n"
585+ "use Vendor\\Pkg\\Auditable as AuditableBase;\n"
586+ "\n"
587+ "trait Auditable {\n"
588+ " use AuditableBase;\n"
589+ "\n"
590+ " function f() { $x = 1; return $x; }\n"
591+ "}\n" ;
592+ CBMFileResult * r = extract_php (src );
593+ ASSERT (r );
594+ cbm_free_result (r );
595+ PASS ();
596+ }
597+
598+ /* ── 23d. Regression #951: class shares its short name with an aliased
599+ * trait import ──
600+ *
601+ * `use App\Functions\Delivery as Delivery_Trait;` + `class Delivery { use
602+ * Delivery_Trait; ... }` — resolving the composed alias falls back to the
603+ * short name and lands on the LOCAL CLASS `Delivery`, so the class is
604+ * flattened into itself (class_qn == canonical target QN): the same loop
605+ * as 23b/23c reached through a class/trait short-name collision. Reported
606+ * as an indexer OOM kill (exit 137) in issue #951. The two-file original
607+ * reduces to this single-file form because the trait's definition being
608+ * unavailable is exactly what forces the short-name fallback. */
609+ TEST (phplsp_class_aliased_trait_name_collision_terminates ) {
610+ const char * src = "<?php\n"
611+ "namespace App\\Modules\\Foo;\n"
612+ "\n"
613+ "use App\\Functions\\Delivery as Delivery_Trait;\n"
614+ "\n"
615+ "class Delivery {\n"
616+ " use Delivery_Trait;\n"
617+ "\n"
618+ " public function run(): void {\n"
619+ " }\n"
620+ "}\n" ;
621+ CBMFileResult * r = extract_php (src );
622+ ASSERT (r );
623+ cbm_free_result (r );
624+ PASS ();
625+ }
626+
571627/* ── 24. Match expression result type ──────────────────────────── */
572628
573629TEST (phplsp_match_result_type ) {
@@ -5186,6 +5242,8 @@ SUITE(php_lsp) {
51865242 RUN_TEST (phplsp_phpdoc_method_class_tag );
51875243 RUN_TEST (phplsp_trait_method_flattened );
51885244 RUN_TEST (phplsp_trait_self_use_terminates );
5245+ RUN_TEST (phplsp_trait_aliased_import_name_collision_terminates );
5246+ RUN_TEST (phplsp_class_aliased_trait_name_collision_terminates );
51895247 RUN_TEST (phplsp_match_result_type );
51905248 RUN_TEST (phplsp_ternary_result_type );
51915249 RUN_TEST (phplsp_method_chain_depth_three );
0 commit comments