diff --git a/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl b/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl index 600cf0fe..57d46319 100644 --- a/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl +++ b/plugins/axiomcode/skills/axiomcode/scripts/dl/impact.dl @@ -664,8 +664,11 @@ direct(q, m, "reads", w, "resolved", "", 0) :- target(q, "field", fl, _), persis sig_words("METHOD_PARAM", "a parameter"). sig_words("METHOD_RETURN", "the return type"). .decl sig_resolved(q:symbol, c:symbol) sig_resolved(q, c) :- target(q, "type", t, _), sigtype(c, t, _, _), !inside_target(q, c). -direct(q, c, "uses", cat("names it in its signature (", w, ")"), "resolved", "", 0) :- target(q, "type", t, _), sigtype(c, t, ctx, 0), sig_words(ctx, w), !inside_target(q, c). -direct(q, c, "uses", cat("names it in its signature (a type argument of ", w, ")"), "resolved", "", 0) :- target(q, "type", t, _), sigtype(c, t, ctx, d), d > 0, sig_words(ctx, w), !inside_target(q, c). +// a signature typeref already names at its line (the rule above, by name with a site) gets no second, lineless row +.decl sig_at_line(q:symbol, c:symbol, ctx:symbol) +sig_at_line(q, c, ctx) :- target(q, "type", t, _), typ(t, n, _), typeref(c, n, ctx, _, _), sig_words(ctx, _). +direct(q, c, "uses", cat("names it in its signature (", w, ")"), "resolved", "", 0) :- target(q, "type", t, _), sigtype(c, t, ctx, 0), sig_words(ctx, w), !inside_target(q, c), !sig_at_line(q, c, ctx). +direct(q, c, "uses", cat("names it in its signature (a type argument of ", w, ")"), "resolved", "", 0) :- target(q, "type", t, _), sigtype(c, t, ctx, d), d > 0, sig_words(ctx, w), !inside_target(q, c), !sig_at_line(q, c, ctx). direct(q, c, "uses", "names it (a signature or a declaration)", "text", f, l) :- target(q, "type", t, _), typ(t, n, _), textuse(c, n, f, l), !inside_target(q, c), !sig_resolved(q, c). direct(q, c, "uses", cat("uses ", n, ", imported from it"), "by name", f, l) :- target(q, "type", _, _), importuse(c, n, f, l), !inside_target(q, c). direct(q, c, "reads", cat("calls the generated getter ", an, "()"), "by name", f, l) :- target(q, "type", t, _), gen(t, "get"), field(fl, t, _, _, _), accessor(fl, an, "read"), unresolved(c, an, k, f, l), !ctor_kind(k), !inside_target(q, c). diff --git a/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py b/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py index 549f6ebd..1424c15b 100644 --- a/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py +++ b/plugins/axiomcode/skills/axiomcode/scripts/graph_sql.py @@ -2438,8 +2438,9 @@ def direct_for_type(q, tids, at, inside, textuse, importuse, rel, code=None): holder = typeref_holder(at, aspans, {i for (i,) in q("SELECT id FROM symbols WHERE kind = 'module'")} if aspans else set()) def trefs(n): return q("SELECT name, file, line, context FROM type_refs WHERE line > 0 AND name = ?", n) - over, todo = set(), [] - sig_resolved = set() # callables whose signature type_use resolves to it (273b) # alias_over(q, a), and the aliases still to expand + over, todo = set(), [] # alias_over(q, a), and the aliases still to expand + sig_resolved = set() # callables whose signature type_use resolves to it (273b) + sig_at_line = set() # (c, ctx) rule 273 names with a line: 273b adds no second row # ── a type the container INJECTS (rule 186) ──────────────────────────────────────────────────────────── # direct(q,c,"uses",cat("receives it by dependency injection (",kind,") — …"),"resolved","",0) @@ -2566,7 +2567,8 @@ def trefs(n): return q("SELECT name, file, line, context FROM type_refs WHERE li for nm, f, l, ctx in trefs(n): c = holder(f, l) if (c, f, l) in other: continue # typeref_other: the name at that line builds another type of it - if c and c not in inside: rows.append((c, 'uses', f'names it ({ctx})', 'by name', f, l)) + if c and c not in inside: + rows.append((c, 'uses', f'names it ({ctx})', 'by name', f, l)); sig_at_line.add((c, ctx)) if c in anames and c not in inside and c not in over: over.add(c); todo.append(c) # 273b — a signature the engine RESOLVED to this type (#1422): `type_use` holds each parameter, return and # type-argument position with the type it names. Java writes no line into type_refs, so rule 273 matched none of @@ -2579,6 +2581,7 @@ def trefs(n): return q("SELECT name, file, line, context FROM type_refs WHERE li AND context IN ('METHOD_PARAM', 'METHOD_RETURN')""", t): if not c or c in inside: continue sig_resolved.add(c) + if (c, ctx) in sig_at_line: continue # rule 273 already names this signature at its line what = SIG_CTX_WORDS.get(ctx, ctx.lower()) if depth and int(depth) > 0: what = f"a type argument of {what}" rows.append((c, 'uses', f'names it in its signature ({what})', 'resolved', '', 0)) diff --git a/tests/cases/typescript/pipeline-array-dispatch/case.json b/tests/cases/typescript/pipeline-array-dispatch/case.json index 7a5d03bc..f963d5ed 100644 --- a/tests/cases/typescript/pipeline-array-dispatch/case.json +++ b/tests/cases/typescript/pipeline-array-dispatch/case.json @@ -14,8 +14,7 @@ ], "avoid": [ "0 of 1 test method(s)" - ], - "pending": "#967 \u2014 a callable registered as DATA (an array element) has no edge from whoever iterates it; PEND is decided from want/avoid only, so a crash here is still a failure" + ] }, { "why": "the same silence, one hop earlier: the pipeline's own caller is the iterating function", @@ -29,9 +28,7 @@ ], "avoid": [ "no chain of resolved calls" - ], - "pending": "#967 \u2014 a callable registered as DATA (an array element) has no edge from whoever iterates it; PEND is decided from want/avoid only, so a crash here is still a failure", - "expect_error": true + ] } ] -} \ No newline at end of file +}