A Rust call through a chained associated function — `Foo::new().bar()`, `Foo::with(cfg).build()` — dropped the receiver to a bare method name, which then attached to a same-named method on an unrelated type (a wrong edge) or didn't resolve. Ports the #645/#608 mechanism for Rust's `::` receivers: - Part 1: capture Rust return types; `-> Self` yields the `self` marker (resolved to the impl's own type, like PHP), references/generics are unwrapped/reduced. - Part 2: encode an associated-function chain (`Foo::new().bar`), gated to a scoped_identifier receiver so instance chains (`x.foo().bar()`) keep bare-name. - Part 3: resolve via matchScopedCallChain (PHP's `::` resolver, generalized), validated by resolveMethodOnType. Wire Rust into the conformance second pass (matchScopedCallChain variant) so a chained method provided by a trait the type implements (`impl Trait for Type` → existing implements edges) resolves too. Validated: synthetic decoy + args + Self + trait-default-conformance + absent safety tests; full suite green (lone failure is the known-flaky #662 daemon test, passes in isolation). Real-repo A/B vs main: clap (329 .rs) a net precision win — **+937 added (96% correct builder methods), 622 wrong->right retargets** (`Command::new().arg()` was mis-resolving to `ArgGroup::arg`, now `Command::arg`), +162 net unique edges; the pure-drops are largely wrong bare-name edges the fix correctly stops emitting. tokio-rs/bytes 0/0 (no regression). Known limit: the single-hop mechanism re-encodes only the first hop of a chain (deeper hops keep bare-name) — clap's unusually deep builder chains are partly covered. EXTRACTION_VERSION 10 -> 11. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7c7f0dd56f
commit
5805f01957
@@ -2528,18 +2528,19 @@ export class TreeSitterExtractor {
|
||||
(this.language === 'cpp' ||
|
||||
this.language === 'c' ||
|
||||
this.language === 'kotlin' ||
|
||||
this.language === 'swift') &&
|
||||
this.language === 'swift' ||
|
||||
this.language === 'rust') &&
|
||||
receiver &&
|
||||
receiver.type === 'call_expression'
|
||||
) {
|
||||
// Receiver that is itself a call — `Foo::instance().bar()`,
|
||||
// `openSession()->run()`, `mgr.view().render()` (C/C++), or
|
||||
// `Foo.getInstance().bar()` (Kotlin) / `Foo.make().draw()` (Swift).
|
||||
// Keep the inner call so resolution can infer bar()'s class from what
|
||||
// the inner call RETURNS (#645/#608). Encode as `<innerCallee>().<method>`;
|
||||
// the `().` marker never appears in an ordinary ref, so the resolver
|
||||
// can detect and split it. Other languages keep the bare-name
|
||||
// behavior (dropping the receiver) below.
|
||||
// `openSession()->run()`, `mgr.view().render()` (C/C++),
|
||||
// `Foo.getInstance().bar()` (Kotlin) / `Foo.make().draw()` (Swift), or
|
||||
// `Foo::new().bar()` (Rust). Keep the inner call so resolution can
|
||||
// infer bar()'s class from what the inner call RETURNS (#645/#608).
|
||||
// Encode as `<innerCallee>().<method>`; the `().` marker never appears
|
||||
// in an ordinary ref, so the resolver can detect and split it. Other
|
||||
// languages keep the bare-name behavior (dropping the receiver) below.
|
||||
let innerCallee: string;
|
||||
let reencode: boolean;
|
||||
if (this.language === 'kotlin' || this.language === 'swift') {
|
||||
@@ -2561,7 +2562,13 @@ export class TreeSitterExtractor {
|
||||
innerCallee = innerFn
|
||||
? getNodeText(innerFn, this.source).replace(/->/g, '.').replace(/\s+/g, '')
|
||||
: '';
|
||||
reencode = !!innerCallee;
|
||||
// Rust: only re-encode an associated-function chain
|
||||
// (`Foo::new().bar()`), whose inner callee is a path/`scoped_identifier`.
|
||||
// An instance chain (`x.foo().bar()`, inner callee a field_expression)
|
||||
// keeps bare-name — the `::` resolver can't recover a variable's type,
|
||||
// so re-encoding would only drop the edge. C/C++ re-encode any inner.
|
||||
reencode =
|
||||
this.language === 'rust' ? innerFn?.type === 'scoped_identifier' : !!innerCallee;
|
||||
}
|
||||
calleeName = reencode ? `${innerCallee}().${methodName}` : methodName;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user