You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
C# namespaces are not represented in the graph's C# identity. parent_name holds only the containing-type path, and the only namespace evidence is csharp_namespaces_by_file — a set of every namespace a file declares. The resolver therefore cannot establish which namespace a given type actually sits in, which makes namespace-sensitive call resolution undecidable in both directions: it fabricates edges for types the caller cannot name, and it cannot safely reject them without also rejecting valid calls.
This is long-standing behaviour, not a regression. It became visible during review of #937 (nested type identity, #934), where four consecutive rounds each closed one instance of it. It should be fixed at the cause.
parent_name = App.Report.ExportHandler
file = Indexed.cs
namespaces = {"Other"} # per file, not per node
Other has been erased from the key. A caller meaning an entirely different App.Report.ExportHandler — typically from a referenced assembly that was never indexed — matches this node exactly.
Failing cases
All of these reproduce on main. Each was verified during #937 review.
Exact path, wrong namespace. Receiver App.Report.ExportHandler, candidate above. main resolves it (on the bare name ExportHandler); fix(parser): preserve full C# nested type identity #937 narrows it to requiring the whole containing path to coincide, but still resolves it. Should be unresolved.
Same file, different namespaces. File co-location does not imply visibility in C#; a type in namespace Other is not nameable from namespace ConsumerNamespace in the same file without a using. Currently resolves.
Multi-namespace file. A file declaring both App and Other cannot show which namespace encloses a candidate. fix(parser): preserve full C# nested type identity #937 handles this conservatively — it requires the dropped namespace to be the file's only namespace — so genuine matches in such files are left unresolved. A false negative, chosen over a fabricated edge.
using scoped to a namespace body.imports_by_file collapses every IMPORTS_FROM edge in a file into one set, but the spec scopes an ordinary using to its immediately containing compilation unit or namespace body. A using Other; inside namespace A is currently indistinguishable from one that applies to namespace B in the same file.
Project-wide global using. A global using Other; in a separate file applies to every compilation unit. Any visibility check keyed on the caller's own file will wrongly reject these.
Cases 1, 2 and 4 over-permit; 3 and 5 under-permit. They share one cause.
Prior attempt
_csharp_namespace_visible() (2fb7b6d, reverted in 01371fe) tried to decide visibility from file-level evidence: same file, global namespace, a using in the caller's file, or a namespace the caller declares. It simultaneously
regressed case 5 — a valid global using call resolved on main and became unresolved, and
failed to fix cases 1, 2 and 4 — still over-permitting.
Being wrong in both directions at once is the evidence that the granularity, not the rule, is the problem. It was reverted rather than extended.
Proposed direction
Persist the declaring namespace per type/method rather than per file, and resolve against (namespace, containing-type path) instead of the containing-type path alone.
Open design questions worth settling before implementation:
Identity vs. sidecar. Whether the namespace joins qualified_name (a C# identity-format change, so it needs the CSHARP_IDENTITY_VERSION rebuild gate that fix(parser): preserve full C# nested type identity #937 already uses) or lands as a separate indexed column resolved against. The sidecar is cheaper and avoids re-spelling every C# node; the identity change makes wrong-namespace collisions impossible by construction.
Scoped usings.IMPORTS_FROM needs to record the namespace body a using applies to, otherwise case 4 stays undecidable.
Global usings. These need to be collected project-wide and unioned into every compilation unit's visible set, otherwise fixing cases 1–4 will regress case 5 exactly as the reverted attempt did.
Conservative default. When evidence is still insufficient, leave the call unresolved rather than guess — consistent with the resolver's existing policy.
Existing coverage
Two tests on the #937 branch already pin the boundary and should be honoured by any fix:
test_exact_path_match_should_check_the_candidate_namespace — currently xfail, documents case 1, flips to passing when this is fixed
test_global_using_target_still_resolves — guards case 5 against a repeat of the reverted approach
Summary
C# namespaces are not represented in the graph's C# identity.
parent_nameholds only the containing-type path, and the only namespace evidence iscsharp_namespaces_by_file— a set of every namespace a file declares. The resolver therefore cannot establish which namespace a given type actually sits in, which makes namespace-sensitive call resolution undecidable in both directions: it fabricates edges for types the caller cannot name, and it cannot safely reject them without also rejecting valid calls.This is long-standing behaviour, not a regression. It became visible during review of #937 (nested type identity, #934), where four consecutive rounds each closed one instance of it. It should be fixed at the cause.
Why the current evidence is insufficient
Given:
the method is stored as:
Otherhas been erased from the key. A caller meaning an entirely differentApp.Report.ExportHandler— typically from a referenced assembly that was never indexed — matches this node exactly.Failing cases
All of these reproduce on
main. Each was verified during #937 review.Exact path, wrong namespace. Receiver
App.Report.ExportHandler, candidate above.mainresolves it (on the bare nameExportHandler); fix(parser): preserve full C# nested type identity #937 narrows it to requiring the whole containing path to coincide, but still resolves it. Should be unresolved.Same file, different namespaces. File co-location does not imply visibility in C#; a type in
namespace Otheris not nameable fromnamespace ConsumerNamespacein the same file without ausing. Currently resolves.Multi-namespace file. A file declaring both
AppandOthercannot show which namespace encloses a candidate. fix(parser): preserve full C# nested type identity #937 handles this conservatively — it requires the dropped namespace to be the file's only namespace — so genuine matches in such files are left unresolved. A false negative, chosen over a fabricated edge.usingscoped to a namespace body.imports_by_filecollapses everyIMPORTS_FROMedge in a file into one set, but the spec scopes an ordinaryusingto its immediately containing compilation unit or namespace body. Ausing Other;insidenamespace Ais currently indistinguishable from one that applies tonamespace Bin the same file.Project-wide
global using. Aglobal using Other;in a separate file applies to every compilation unit. Any visibility check keyed on the caller's own file will wrongly reject these.Cases 1, 2 and 4 over-permit; 3 and 5 under-permit. They share one cause.
Prior attempt
_csharp_namespace_visible()(2fb7b6d, reverted in 01371fe) tried to decide visibility from file-level evidence: same file, global namespace, ausingin the caller's file, or a namespace the caller declares. It simultaneouslyglobal usingcall resolved onmainand became unresolved, andBeing wrong in both directions at once is the evidence that the granularity, not the rule, is the problem. It was reverted rather than extended.
Proposed direction
Persist the declaring namespace per type/method rather than per file, and resolve against
(namespace, containing-type path)instead of the containing-type path alone.Open design questions worth settling before implementation:
qualified_name(a C# identity-format change, so it needs theCSHARP_IDENTITY_VERSIONrebuild gate that fix(parser): preserve full C# nested type identity #937 already uses) or lands as a separate indexed column resolved against. The sidecar is cheaper and avoids re-spelling every C# node; the identity change makes wrong-namespace collisions impossible by construction.IMPORTS_FROMneeds to record the namespace body ausingapplies to, otherwise case 4 stays undecidable.Existing coverage
Two tests on the #937 branch already pin the boundary and should be honoured by any fix:
test_exact_path_match_should_check_the_candidate_namespace— currentlyxfail, documents case 1, flips to passing when this is fixedtest_global_using_target_still_resolves— guards case 5 against a repeat of the reverted approachContext