fix(resolution): a definition its language makes file-local is not a cross-file target - #1732
fix(resolution): a definition its language makes file-local is not a cross-file target#1732danusha2345 wants to merge 2 commits into
Conversation
…cross-file target
Name matching accepted any same-named definition as the target of a call
from another file, however the language scopes it. isVisibleAcrossFiles
now declines, for a candidate in another file:
C / C++ a function whose definition line carries `static` (read from
source — the extractor records no storage class, and the kernel
arm would need the same field)
Kotlin, Java, C#, Swift, Scala, Dart, PHP
visibility === 'private'
Go a lowercase identifier from another directory (by the name's
case: the extractor's isExported is unset for every Go method)
Rust a non-`pub` item unless the reference is in the item's module
subtree (a child sees its ancestors' private items via super::);
a method in an `impl Trait for Type` block has the trait's
visibility and is exempt
The test runs in ReferenceResolver on the target the whole name-matching
pipeline settled on, so a rejection ends the reference unresolved. Declining
inside matchByExactName instead let the ref fall through to matchFuzzy,
which committed to a same-language namesake the ranking had passed over —
eight edges on one tree, all onto a local `const fail = …` arrow the graph
does not hold. matchFuzzy checks its own survivor too; nothing runs after it.
Five corpora, all against b9ca4b7, wasm arm, edge rows keyed with
resolvedBy:
betaflight fork (2,109 C files) LOST 4,451 GAINED 0 (colbymchenry#1730)
Android/Go/JS app (114 kt, 42 go) LOST 142 GAINED 0 (colbymchenry#1731)
emmc-reader-gui (71 rs) LOST 195 GAINED 0
skylab_hub (35 rs) LOST 92 GAINED 0
vitejs/vite (JS/TS only) LOST 0 GAINED 0
Samples read back: `Vec::new()` onto a private `fn new` in another crate,
`ui.add(…)` (egui) onto a private `add`, `latch.await()` onto a test file's
`private fun await`, `leaflet.js` onto an unexported Go `func add`,
`usbd_get_descriptor` onto a `static get_device_descriptor` in a USB class
file it never links.
Fixes colbymchenry#1730. Fixes colbymchenry#1731.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…udes it The C rule declined any `static` function defined in another file. A `static` in a SOURCE file is local to that translation unit and the rule is right there; a `static` in a header — `static inline`, the whole of MAVLink's generated `mavlink_msg_*.h` — is textually included into every unit that names it, and the call is real. On the betaflight tree 4,306 of the 4,451 rows the first cut removed were exactly that: `testsuite.h` and `mavlink_msg_*.h` calling `protocol.h`'s `_mav_put_char_array`, `mav_array_assign_char` and each other's `_pack` / `_decode` helpers. The rule now applies only to a candidate whose file is a translation unit (`.c .cc .cpp .cxx .c++ .m .mm`). Same tree: LOST 145, GAINED 0, every one onto a `static` in another `.c` — STM32 USB class sources onto GD32's `usbd_enum.c`, and the USB descriptor table shape from colbymchenry#1730. Header targets in the removed set: 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Correction, pushed as Of the 4,451 rows it removed, 4,306 targeted a The rule now applies to candidates in a source file ( I'll correct #1730's count there too; the 10% figure in it was counting the header calls. |
Fixes #1730. Fixes #1731. Standalone off
main(b9ca4b7), two commits — the second narrows the C rule to translation units after the first cut removed 4,306 real calls onto headerstatic inlines; details in the comment below.What
Name matching accepted any same-named definition as the target of a reference from another file, however the language scopes that definition. One test,
isVisibleAcrossFiles, now declines a candidate in another file when:.c .cc .cpp .cxx .m .mm) and its definition line carriesstatic— a header'sstatic inlineis textually included into every unit that names it and stays visiblevisibility === 'private'isExportedis unset for every Go method, exported or notpubitem and the reference is outside the item's module subtreesrc/net.rs/src/net/mod.rsownsrc/net/; a child reaches its ancestors' private items viasuper::. A method in animpl Trait for Typeblock has the trait's visibility and is exempt (read from the enclosingimplheader)Same-file candidates are always visible.
Where the test runs, and why there
In
ReferenceResolver, on the target the whole name-matching pipeline settled on (exact-match,fuzzy,instance-method,qualified-nameall come through it), so a rejection ends the reference unresolved. The first cut declined insidematchByExactName, #1720-style, and that let the ref fall through tomatchFuzzy, which committed to a same-language namesake the ranking had passed over: eight new fuzzy edges on one tree, every one onto a JavaScriptfailin a different file, the realfailbeing a localconst fail = (msg) => …the graph does not hold (#1669's shape).matchFuzzychecks its own survivor as well, since nothing runs after it.Measurement
Five corpora, each indexed at
b9ca4b7and at this branch (wasm arm), edge rows joined back to symbols and keyed withresolvedBy:.c.kt, 42.go, 96.js.rs.rs, 4.ktRead back from source, the removals are the shapes in the two issues: STM32 USB class sources →
statichandlers in GD32'susbd_enum.c,usbd_get_descriptor→ astatic get_device_descriptorin a USB class file it never links;editor.apply()→ an unrelated class'sprivate fun apply;latch.await()in tests → a test file'sprivate fun await(×8);leaflet.js/validate.mjs→ unexported Goadd/join(55 cross-language rows);Vec::new()→ a privatefn newin another crate (×7);ui.add(…)(egui) → a privateadd;f.finish()→HashingWriter::finishin another crate. The Rust breakdown after the trait exemption: 171instance-method, 8exact-matchcalls, 16references— none onto a trait-impl method.Not touched: the Go extractor's
isExportedon methods (a separate extractor defect noted in #1731), the C storage class as a node field, and the local-closure gap behind the JSfail(#1669).Tests
__tests__/cross-file-visibility.test.ts, whole pipeline over source fixtures, each invisible shape paired with the visible one of identical form: Cstaticin another source file vs non-static vs a header'sstatic inline(kept) vs same-filestaticwith the keyword on its own line; Kotlinprivate fun applyreached through an SDK-styleeditor.apply()vs a publicfun applyon a typed receiver; Go unexported func across packages vs within the package and an exported func elsewhere; Rust a sibling module's private fn vs a parent's private fn from a child, a trait-impl method through a typed receiver, and apub fnanywhere. 11 cases.resolution.test.ts,frameworks-integration.test.ts,pr19-improvements.test.tsunchanged: 200 acrosscross-file-visibility+resolution.test.ts,tscclean.🤖 Generated with Claude Code