Repository navigation
fix(java,csharp): a call on a new object reaches the class the file imports, not a namesake - #2864
Merged
Merged
Conversation
…mports, not a namesake PR #2854 sends Java's and C#'s no-argument new Foo().bar() calls, which the chain conformance pass retries, to the constructed-receiver resolver. That links them (mybatis-3 +265, Newtonsoft.Json, serilog and jellyfin +36, all right), but the hint for which Foo it passed was a file path, which the resolver reads for these languages as a dotted package name, and C#'s using names namespaces, not classes. So of two classes named Foo the first indexed one won, whatever the file imported: import b.Foo; new Foo().bar() linked a.Foo::bar at 0.9, and so did a call the language itself cannot resolve, after import a.*; import b.*;. When several project classes share the name, Java and C# now pick as the language does: Java the written package (new a.Foo()), the file's single-type import, else the caller's own package; C# the one type the file's namespaces and usings can see. Only that class's own method links, otherwise nothing. A name only one class has resolves as before, inherited methods included. Validation: the new test fails 4 of 4 on main 44adef8 with the kernel and with CODEGRAPH_KERNEL=0 (import b.Foo linked a.Foo::bar, and the ambiguous calls linked a.Foo and A.Foo), and passes here with both; new-expression-receiver and kernel-tsjs-parity pass. A/B against main, kernel per arm: flask, mybatis-3, Newtonsoft.Json, serilog and jellyfin byte-identical, so the 301 links PR #2854 added there stay, mybatis-3's 2 calls on a class with a same-named copy in another package among them, which resolve to the caller's own package as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A Java or C# method called on a newly constructed object,
new Foo().bar(), now links to the class the language picks when several packages or namespaces declare a class of that name, and to nothing when the language itself can't tell. A follow-up to #2854.Root cause
#2854 sends a constructed receiver,
new Foo().m, to a new resolver, and the conformance pass routes that shape there for every language whose chain calls it retries. Java and C# emit the shape for a no-argument constructor (new SqlSessionFactoryBuilder().build(reader)), so they started linking those calls too: mybatis-3 +265, and Newtonsoft.Json, serilog and jellyfin +36, all of them right. But the hint for whichFoowas a file path from the TS/JS import reader. For these languages,resolveMethodOnTypereads that hint as a dotted package name, and C#'susingnames namespaces rather than classes. So with two classes namedFoo, the first indexed one won, at 0.9, whatever the file imported:A call the language itself rejects as ambiguous (
import a.*; import b.*;,using A; using B;) linked one too.Fix
matchNewReceiverCallhands Java and C# tomatchJavaCsharpNewReceiverCall:new a.Foo()), then the file's single-type import, then the caller's own package.isCsharpTypeVisible).Validation
New test,
new-receiver-twin-classes.test.ts(Java and C#):import a.*; import b.*;,using A; using B;);On main 44adef8 it fails 4 of 4 with the kernel and with
CODEGRAPH_KERNEL=0:import b.Foolinkeda.Foo::bar,using BlinkedA.Foo::Bar, and both ambiguous calls linked thea/Acopy. It passes 4 of 4 here with both engines.new-expression-receiverandkernel-tsjs-paritypass with the kernel.A/B against main 44adef8 (graph dumps by natural keys, kernel per arm): flask, mybatis-3 (Java), Newtonsoft.Json, serilog and jellyfin (C#) are byte-identical. All 301 Java/C# links fix(js,ts): a call on a new C() receiver resolves through C #2854 added in those repos stay. That includes mybatis-3's
CglibProxyFactory/JavassistProxyFactorycalls, whose class has a same-named copy in another package; they resolve to the caller's own package as before. Main has since moved to 43a4f5b by commits that touch only file scope, the type hierarchy and the context builder; the rebase left the changed lines identical.Suite (
CODEGRAPH_KERNEL_EXPECT=1 npx vitest run --maxWorkers=4 --minWorkers=1,CODEGRAPH_NO_DAEMONunset, on this commit): 762 files, 9,069 tests, 8,987 passed, 0 failed, 82 skipped.🤖 Generated with Claude Code