Commit Graph
6 Commits
Author SHA1 Message Date
JensD-git ab8d63bf4c fix(csharp): salt colliding ids before the partial merge, so a half keeps its members (#4411)
Two files can mint the same stem (`Spec.cs` / `_Spec.cs`, `Cfg/Helpers.cs` /
`Cfg_Helpers.cs`), so the type ids in them collide. The C# partial merge ran
before _disambiguate_colliding_node_ids: it rewired the edges of every half
onto the canonical half's still-colliding id, and the disambiguation, which
remaps by (id, source_file of the edge), then missed every edge that came from
another half and left it on a dead id. The members of that half had no owning
type. When both colliding files declared a half of the same partial type, the
second node kept the canonical id, was not removed by the merge, and was split
off again, so the type stayed two nodes. And since the merge removes
merged-away halves by id, an unrelated node in another file that shared such
an id was removed with them.

Run the disambiguation first. Every edge is still on its own half when ids are
salted, and the merge joins the halves by type path, whatever their ids.

Fixes #4411.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 78575576a8)
2026-10-13 22:21:43 +01:00
JensD-git d85cb85654 fix(csharp): keep id-sharing and qualified-base partials out of the merge (#4363)
Follow-ups from the automated review of the first commit:

- Two same-named nested types under different outers in one file share one
  node id. That node took the first declaration's type_path and could join
  the other outer's halves; it now gets no type_path and is not merged.
- The shadowed-base step drops only a placeholder spelled with the bare
  name. A base written qualified (Other.IFoo), or through a using alias of
  that name, can be a different type that only shares the simple name, and
  keeps its edge.
- Pin that receiver-qualified calls (base.M(), this.M(), Type.M(), obj.M())
  keep their targets: they leave the cross-file pass as member calls before
  the own-type binding.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 37ec971f16)
2026-10-12 14:50:32 +01:00
JensD-git 371cb47e83 fix(csharp): merge nested and generic partial types by their full type path (#4363)
The partial merge grouped halves by (namespace, label) and skipped nested
types, because nested ids omit the enclosing type. A nested partial type split
across files stayed split, and `Box` / `Box<T>` partials were folded into one
node although they are distinct types (#4249).

- The C# extractor records each partial type's path inside its namespace,
  enclosing types first, each with its arity (`Outer`1.Inner`), as
  metadata.type_path; the merge keys on (assembly, namespace, type_path).
- The cross-file call pass binds a C# unqualified call to the one candidate
  that is a member of the caller's own type, so a call into another half of a
  partial type is not lost to a same-named method elsewhere (#4252 does this
  in-file only). Ties fall through unchanged.
- After C# type resolution, a merged partial type drops a placeholder base
  that sits next to a real base of the same name; one half resolving a sibling
  nested base and the other not left two bases, and base-chain lookups failed.
- _AST_CACHE_SCHEMA 8 -> 9, so cached C# results without type_path are
  re-extracted.

Fixes #4363.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 92d9197787)
2026-10-12 14:50:32 +01:00
rohit-jsfreaky 117e6b4bad fix(extract): keep recursive calls when merging C# partial classes
_merge_csharp_partial_class_nodes rewrote every edge in the corpus and
dropped every self-loop, so one partial class split across two files
erased recursive calls in every language of the repo. It also deduped
edges it never rewrote, on a key that ignores confidence and context.

Keep edges the merge does not remap verbatim (the Swift extension merge
rule, #2538) and drop a self-loop only when two distinct endpoints
collapse into one node (the deduplicate_entities rule, #3809), so a
pre-existing self-loop on a merged-away half is rewired, not lost.

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 5992044f32)
2026-10-04 02:07:00 +01:00
safishamsiandClaude Opus 4.8 4e7e6b1f7e fix(extract,watch): C# assembly-aware partial merge, incremental edge preservation, extract crash recovery; bump to 0.9.33
#2411 (thanks @JensD-git): key the C# partial-class merge on assembly
(nearest ancestor .csproj/.fsproj/.vbproj) in addition to namespace and
name, so same-name partial classes in different assemblies stay distinct
while genuine partial halves within one project still merge. Fixes a
0.9.32 regression from #2332.

#2437/#2438 (thanks @aryanbonigala, builds on PR #2439): incremental
rebuilds no longer drop member-call and indirect_call edges from a
changed file into an unchanged target. Re-resolution now sees the
unchanged corpus (nodes, contains/method edges, and _callable markers,
which now persist to graph.json like _origin); edges to a genuinely
removed target are still evicted.

#2444/#2445 (thanks @Baziar, builds on PRs #2461/#2458): a
BrokenProcessPool triggers the sequential fallback instead of being
swallowed per future, a failed worker file is retried sequentially
rather than merged as empty, and a whole-pass AST failure on a fresh
build exits non-zero instead of writing a zero-node graph
(--allow-partial opts into a best-effort partial graph).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-05 01:41:12 +01:00
safishamsiandClaude Opus 4.8 4a9613f726 fix(extract): C# inline-declared + partial-class receivers, Kotlin anonymous-object members (#2346, #2332, #2347)
- C# receivers declared inline via out-var / is / case / switch-arm patterns
  are now typed into the per-method table, so their member calls resolve (#2346).
- partial class halves across files now merge to one class node (new
  _merge_csharp_partial_class_nodes pass, mirroring the Swift-extension merge),
  so cross-half member calls resolve instead of splitting the class (#2332).
- Kotlin anonymous-object (object : Foo {}) members now get nodes, contains/
  implements edges, and their calls resolve (#2347).
All in-corpus only, never a wrong edge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 12:21:04 +01:00