Skip to content

fix(scanner): resolve go.mod per-file, closing issue #17#24

Merged
flaglint merged 1 commit into
mainfrom
fix/nested-gomod-submodules
Jul 7, 2026
Merged

fix(scanner): resolve go.mod per-file, closing issue #17#24
flaglint merged 1 commit into
mainfrom
fix/nested-gomod-submodules

Conversation

@flaglint

@flaglint flaglint commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #17. findModule was called once for the whole scan, from the scan root — so every file's Go import path was computed relative to whichever go.mod happened to be nearest the scan root, even for files under an independent nested submodule (a monorepo containing its own go.mod deeper in the tree). A cross-package factory call from outside the submodule into it would never resolve, since the submodule's own files' computed import paths were wrong (relative to the wrong module entirely).

Fix

Search upward from each file's own directory instead of the scan root once — a file under a submodule now correctly finds that submodule's own (nearer) go.mod before ever reaching the outer one. Added a moduleCache (memoizing the search per-directory) since this is now called once per file rather than once per scan; files sharing the same nearest go.mod (the overwhelmingly common case, one module per repo) still resolve in a single map read after the first lookup in that directory subtree.

Also removed runWholeScanAnalysis's now-dead absRoot parameter (no longer needed now that go.mod resolution is per-file) rather than leave an unused one around.

Verification

  • New fixture (testdata/fixtures/monorepo/) with a genuinely nested go.mod (a real, separate module github.com/example/monorepo-submodule a few directories below flaglint-go's own go.mod) proves a cross-package factory call into the submodule now resolves correctly.
  • Full test suite green.
  • Re-verified against weaviate (a real 4500+-file, single-module repo): same 4 real usages, no measurable performance regression (~2s, unchanged) — confirming the per-directory cache keeps the common case just as fast as the old single-lookup version.

findModule was called once for the whole scan, from the scan root — so
every file's Go import path was computed relative to whichever go.mod
happened to be nearest the scan root, even for files under an independent
nested submodule (a monorepo containing its own go.mod deeper in the
tree). A cross-package factory call from outside the submodule into it
would never resolve, since the submodule's own files' computed import
paths were wrong (relative to the wrong module entirely).

Fixed by searching upward from each file's own directory instead of the
scan root once — a file under a submodule now correctly finds that
submodule's own (nearer) go.mod before ever reaching the outer one. Added
a moduleCache (memoizing the search per-directory) since this is now
called once per file rather than once per scan; files sharing the same
nearest go.mod (the overwhelmingly common case, one module per repo)
still resolve in a single map read after the first lookup in that
directory subtree.

runWholeScanAnalysis no longer needs absRoot at all now that go.mod
resolution is per-file — removed the now-dead parameter (and the
now-dead absRoot computation in the parseFixtures test helper) rather
than leave an unused one for a future unparam lint failure to catch.

Verified: new fixture (testdata/fixtures/monorepo/) with a genuinely
nested go.mod (a real, separate "module github.com/example/monorepo-
submodule" a few directories below flaglint-go's own go.mod) proves a
cross-package factory call into the submodule now resolves correctly.
Full test suite green, and re-verified against weaviate (a real
4500+-file, single-module repo) — same 4 real usages, no measurable
performance regression (~2s, unchanged), confirming the per-directory
cache keeps the common case just as fast as the old single-lookup
version.

Fixes #17

Signed-off-by: Krishan Kant Sharma <krishansharma0327@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@flaglint, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 841b8033-d0c8-4ada-96ee-78666c503846

📥 Commits

Reviewing files that changed from the base of the PR and between c267d60 and 6cb5de0.

📒 Files selected for processing (6)
  • internal/scanner/module.go
  • internal/scanner/scanner.go
  • internal/scanner/scanner_test.go
  • internal/scanner/testdata/fixtures/monorepo/consumer/main.go
  • internal/scanner/testdata/fixtures/monorepo/submodule/go.mod
  • internal/scanner/testdata/fixtures/monorepo/submodule/producer/client.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/nested-gomod-submodules

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@flaglint flaglint merged commit 8e4373b into main Jul 7, 2026
13 checks passed
@flaglint flaglint deleted the fix/nested-gomod-submodules branch July 7, 2026 16:06
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.

scanner: nested go.mod files within a scanned tree break cross-package import-path resolution

2 participants