feat(rust_analyzer): treat crates from locally-overridden modules as workspace members - #4214
Draft
lsjostro wants to merge 1 commit into
Draft
feat(rust_analyzer): treat crates from locally-overridden modules as workspace members#4214lsjostro wants to merge 1 commit into
lsjostro wants to merge 1 commit into
Conversation
…workspace members
Modules declared with local_path_override (or --override_module) have
their sources in a checkout the user edits directly, surfaced through a
symlink at {output_base}/external/<repo>/. The rust-analyzer aspect
classifies every crate under external/ as a non-member, so rust-analyzer
shows no diagnostics for these first-party crates.
Ask Bazel which external repos are local overrides: `bazel mod graph
--output json` marks modules with non-registry overrides with the
version placeholder `_` in their key, and `bazel mod dump_repo_mapping`
resolves module names to canonical repo names. Repos whose directory is
a symlink (what path-based overrides produce, unlike git_override /
archive_override fetches) are treated as local.
Crates under those roots are marked as workspace members, and their
root_module and source.include_dirs are canonicalized in lockstep so
rust-analyzer's textual file-to-crate mapping works with the real paths
editors put in file URIs.
The override set is hashed into the merge cache key (and the schema
version bumped): flipping an override does not necessarily change any
crate spec content, so it must invalidate the cache on its own. In
WORKSPACE mode `bazel mod` is unavailable; detection degrades to the
previous behavior.
Fixes bazelbuild#4213.
Assisted-by: Claude (Anthropic AI assistant)
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.
Fixes #4213 (the Bug 2 follow-up from #4057). Opening as a draft — this is a concrete proposal for the direction discussion in the issue; happy to rework or split it based on feedback.
Problem
Crates from modules declared with
local_path_override(or--override_module) are first-party code the user edits daily, but they sit under{output_base}/external/<repo>/, so the aspect marks themis_workspace_member: falseand rust-analyzer shows no diagnostics for them.Approach
This implements the "combined" option from #4213: ask Bazel which repos are really local overrides, and only touch crates under those repos.
Detection (
tools/rust_analyzer/overrides.rs, new):bazel mod graph --output json— modules with a non-registry override render with the version placeholder_in theirkey(e.g.mypkg@_; theversionfield still carries the declared version, so the key is the only reliable marker). The whole graph is walked, so overrides of transitively-used modules are found too.bazel mod dump_repo_mapping ''— resolves module names to canonical repo names authoritatively, instead of hard-coding a canonical-name scheme that has changed across Bazel versions. (Fallback<name>+for overridden modules not visible from the root module.)git_override/archive_overridefetches, which are not editable checkouts.bazel modfails; detection logs at debug level and degrades to today's behavior.Assembly (
rust_project.rs): crates whoseroot_modulefalls under a detected root are marked workspace members, and theirroot_module+source.include_dirsare canonicalized in lockstep — editors put the real path in file URIs and rust-analyzer's file→crate mapping compares paths textually; canonicalizing only one of the two breaks the mapping and every item from the crate resolves as an unresolved import (we learned this in production). Generated sources live underbazel-out/, never under an override root, so they are untouched.Cache (
cache.rs): the override set is hashed into the merge cache key and the schema version is bumped. Flipping an override does not necessarily change any crate spec content (the canonical repo name — and thus every path in the specs — can stay identical), so it must invalidate the cache on its own.Cost
Two extra
bazel modinvocations per project generation (no analysis, answered by the running server); the second one is skipped when no overrides exist.Known limitation
The aspect only emits
buildinfo (labels for runnables/flycheck) for crates it considers local, so override-module crates gain diagnostics but not codelens runnables. That would need an aspect-side change and feels like a separate discussion.Testing
bazel test //tools/rust_analyzer:gen_rust_project_lib_test(51 tests) and//tools/rust_analyzer:gen_rust_project_clippypass; rustfmt clean.bazel modoutput shapes were verified against a real Bazel 9 bzlmod workspace with fivelocal_path_overridemodules; we run the equivalent of this fix as a patch in our monorepo, where it restores diagnostics for all override-module crates.Per the AI tools policy: prepared with LLM assistance (see
Assisted-bycommit trailer), reviewed and tested by me.