Skip to content
This repository was archived by the owner on Sep 6, 2026. It is now read-only.

Commit afcce2d

Browse files
committed
fix(registry): don't swallow call suffixes on aliased-import direct hits
The DeusData#979 direct-hit early return in resolve_import_map fires before suffix handling, so any imported_symbol.method() call whose base symbol is itself an indexed node resolved to the base node instead of base.method — the exact mis-resolution the neighboring comment warns about. On django this degraded the graph by ~11K edges (CALLS 74,685->72,175, TESTS 38,032->29,236); auth.login => Signal.send became an edge onto the user_logged_in Variable node. Take the direct hit only for suffix-less callees — precisely the aliased direct-symbol import case (DeusData#875) the early return was added for. Verified on django: CALLS 74,708 (baseline + the 23 genuine DeusData#979 wins), TESTS 38,035; the DeusData#979 bare-alias test stays green. Reproduce-first: resolve_import_map_alias_with_suffix_hits_method is RED on the unguarded code (returns the bare symbol QN) and GREEN with the guard. Closes DeusData#1000 Signed-off-by: Martin Vogel <[email protected]>
1 parent 6b57db2 commit afcce2d

2 files changed

Lines changed: 36 additions & 3 deletions

File tree

‎src/pipeline/registry.c‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -618,9 +618,19 @@ static cbm_resolution_t resolve_import_map(const cbm_registry_t *r, const char *
618618
* function name and suffix is NULL, so the target QN must be
619619
* resolved.requireAdmin — not just resolved, which would point at the
620620
* module node and miss the function entirely. */
621-
const char *direct = cbm_ht_get_key(r->exact, resolved);
622-
if (direct) {
623-
return (cbm_resolution_t){direct, "import_map", CONF_IMPORT_MAP, REG_RESOLVED};
621+
/* Direct hit ONLY for suffix-less callees (an aliased direct-symbol
622+
* import called bare: `from m import f as g; g()` — #875/#979). With a
623+
* suffix present (`imported.method()`), returning the bare base here
624+
* would swallow the suffix and bind the call to the imported symbol's
625+
* own node (a Variable/Class/module) instead of base.method — exactly
626+
* the mis-resolution the comment above warns about. That regressed
627+
* django-scale graphs by ~11K CALLS/TESTS edges (Signal.send calls
628+
* degraded to edges onto the signal variables themselves). #1000 */
629+
if (!suffix || !suffix[0]) {
630+
const char *direct = cbm_ht_get_key(r->exact, resolved);
631+
if (direct) {
632+
return (cbm_resolution_t){direct, "import_map", CONF_IMPORT_MAP, REG_RESOLVED};
633+
}
624634
}
625635
char candidate[CBM_SZ_512];
626636
if (suffix && suffix[0]) {

‎tests/test_registry.c‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,28 @@ TEST(tsjs_suppress_keeps_high_confidence_and_non_methods) {
805805

806806
/* ── Suite ─────────────────────────────────────────────────────── */
807807

808+
/* Method call THROUGH an imported symbol that is itself an indexed node
809+
* (`from m import sig; sig.send()`). The import-map value is the symbol QN
810+
* and the callee carries a suffix — resolution must return symbol.send, NOT
811+
* the bare symbol node. The #979 direct-hit early return swallowed the
812+
* suffix whenever the base symbol existed as an exact node, degrading
813+
* django-scale graphs by ~11K CALLS/TESTS edges (e.g. every
814+
* `user_logged_in.send(...)` bound to the signal VARIABLE instead of
815+
* Signal.send). Regression guard for #1000. */
816+
TEST(resolve_import_map_alias_with_suffix_hits_method) {
817+
cbm_registry_t *r = cbm_registry_new();
818+
cbm_registry_add(r, "user_logged_in", "proj.auth.signals.user_logged_in", "Variable");
819+
cbm_registry_add(r, "send", "proj.auth.signals.user_logged_in.send", "Method");
820+
const char *keys[] = {"user_logged_in"};
821+
const char *vals[] = {"proj.auth.signals.user_logged_in"};
822+
cbm_resolution_t res =
823+
cbm_registry_resolve(r, "user_logged_in.send", "proj.auth.views", keys, vals, 1);
824+
ASSERT_STR_EQ(res.qualified_name, "proj.auth.signals.user_logged_in.send");
825+
ASSERT_STR_EQ(res.strategy, "import_map");
826+
cbm_registry_free(r);
827+
PASS();
828+
}
829+
808830
SUITE(registry) {
809831
/* FQN */
810832
RUN_TEST(fqn_simple);
@@ -838,6 +860,7 @@ SUITE(registry) {
838860
RUN_TEST(resolve_import_map);
839861
RUN_TEST(resolve_import_map_bare_function);
840862
RUN_TEST(resolve_import_map_bare_alias);
863+
RUN_TEST(resolve_import_map_alias_with_suffix_hits_method);
841864
RUN_TEST(resolve_unique_name);
842865
RUN_TEST(resolve_unresolved);
843866
RUN_TEST(resolve_many_nodes);

0 commit comments

Comments
 (0)