Skip to content

fix(resolution): a definition its language makes file-local is not a cross-file target (#1731) - #1745

Merged
colbymchenry merged 3 commits into
mainfrom
forge/fix-1731-cross-file-visibility
Sep 8, 2026
Merged

fix(resolution): a definition its language makes file-local is not a cross-file target (#1731)#1745
colbymchenry merged 3 commits into
mainfrom
forge/fix-1731-cross-file-visibility

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Summary

Rebases and lands PR #1732 (danusha2345) onto latest main (post-#1742/#1743), with a small changelog tweak citing #1731 and clarifying the C source-vs-header rule.

Fixes #1731 (Kotlin / Go / Rust). Also covers #1730 (C static in another translation unit).

Name matching accepted any same-named definition as a cross-file target. isVisibleAcrossFiles now declines a candidate in another file when:

language rule
C / C++ function defined in a source file (.c/.cc/…) whose definition carries static — header static inline stays visible
Kotlin, Java, C#, Swift, Scala, Dart, PHP visibility === 'private'
Go lowercase identifier and a different directory (by name case — extractor isExported is unset for methods; see #1734)
Rust non-pub and the ref is outside the item's module subtree; child→ancestor and impl Trait for Type methods stay resolvable

Applied in ReferenceResolver after matchReference settles (and inside matchFuzzy), so rejection leaves the ref unresolved instead of falling through to a fuzzy namesake.

Credits: implementation from #1732 by @danusha2345 / Claude.

Test plan

  • Linux repro on main: Kotlin editor.apply() → private apply, Go cross-package fail, Rust sibling private count all wrongly resolved
  • Same fixtures on this branch: all three declined (KOTLIN_CALLEES [], GO_CALLEES [], RUST_SIBLING_CALLEES [])
  • CODEGRAPH_KERNEL=0 npx vitest run __tests__/cross-file-visibility.test.ts — 11 passed (Node 22.19)
  • CODEGRAPH_KERNEL=0 npx vitest run __tests__/resolution.test.ts — 189 passed

danusha2345 and others added 3 commits September 8, 2026 04:56
…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   (#1730)
  Android/Go/JS app (114 kt, 42 go)      LOST   142  GAINED 0   (#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 #1730. Fixes #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 #1730. Header
targets in the removed set: 0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rebased #1732 onto latest main. Clarify that only a static in another
source file is declined (header static inline stays), name the Kotlin/Go/Rust
shapes from #1731, and note the post-pipeline placement that avoids fuzzy
fallback.
@colbymchenry

Copy link
Copy Markdown
Owner Author

Related open PR #1734 fixes Go method isExported in the extractor; this PR intentionally judges Go by name case so it does not depend on #1734. Once #1734 lands the flag and case agree.

@colbymchenry
colbymchenry merged commit 2c251e2 into main Sep 8, 2026
@colbymchenry
colbymchenry deleted the forge/fix-1731-cross-file-visibility branch September 8, 2026 05:00
bompus added a commit to bompus/codegraph that referenced this pull request Sep 8, 2026
Upstream re-landed four of the fork's changes under its own commits today
(colbymchenry#1697 directly; colbymchenry#1766, colbymchenry#1767, colbymchenry#1769 rebased from the closed colbymchenry#1710, colbymchenry#1706,
colbymchenry#1695), so the fork carried a second copy of each and the hourly sync stopped
with nine conflicts. Upstream's version wins wherever it now owns the change.

take upstream, drop the fork's duplicate:
  src/bin/codegraph.ts        capPromptHookInjection() supersedes the inline
                              MAX = 9000 the fork carried from colbymchenry#1695.
  src/extraction/tree-sitter.ts  CommonJS export assignment support (colbymchenry#1675);
                              the fork had no version of it.
  src/resolution/name-matcher.ts  comment-only conflict; upstream's text
                              already covers colbymchenry#1745, colbymchenry#1719, colbymchenry#1714, colbymchenry#1230,
                              colbymchenry#1708 and colbymchenry#1709.

keep the fork's version, upstream has none:
  src/mcp/tools.ts            the codegraph_sessions tool definition (colbymchenry#1702).
  README.md                   documents that alwaysLoad also covers
                              codegraph_sessions.
  __tests__/fixtures/kernel-parity/torture.tsx   markdown-path fixture.

union, upstream entry first:
  CHANGELOG.md                per UNION_MERGE_FILES.
  __tests__/fixtures/kernel-parity/torture.js    the fork's colbymchenry#693 initializer
                              walks and upstream's colbymchenry#1675 CommonJS exports are
                              different fixtures at the same point in the file.
  __tests__/fuzzy-lexical-reach.test.ts   add/add: both sides created it.
                              Upstream's C-nesting test plus the fork's two
                              sealed-module tests, with the one test both
                              sides wrote kept once.

Verified on Windows against a release build of the kernel: tsc --noEmit
clean, npm run build clean (engine, UI, 29 wasm grammars), full native suite
4438 passed of 4483. The single failure is a refresh-launcher timeout that
passes in 2.7s when the file is run on its own.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kotlin, Go, Rust: a private / unexported / non-pub definition is accepted as a cross-file name-match target

1 participant