This issue was created with AI assistance and has been human reviewed for accuracy before filing.
Description
rust-project.json generation can merge distinct Rust crates that happen to share the same crate_id.
The current consolidation logic in tools/rust_analyzer/aquery.rs::consolidate_crate_specs uses only CrateSpec.crate_id as the map key. crate_id is derived from the crate root module path, so sharing it is intentional for some cases, such as rust_test(crate = ":lib"). However, the same crate_id can also occur for crates that should remain distinct.
Current wrong behavior:
A standalone rust_binary and rust_test using the same root file are consolidated into one rust-analyzer crate. The resulting crate can contain mixed metadata from both targets. In the repro below, the generated crate has display_name = "app", but env.KIND = "test", env.CARGO_CRATE_NAME = "app_test", and build.label = "//:app_test".
Expected behavior:
rust-project.json should only merge crate specs when they represent the same logical rust-analyzer crate, such as the existing rust_test(crate = ":lib") case. Distinct same-root standalone binary/test crates should remain separate entries.
Reproduction steps
Create a minimal workspace using upstream, unpatched rules_rust.
MODULE.bazel:
module(name = "ra_crate_id_repro")
bazel_dep(name = "rules_rust", version = "0.71.3")
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(edition = "2021")
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")
BUILD.bazel:
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test")
rust_binary(
name = "app",
srcs = ["main.rs"],
rustc_env = {"KIND": "binary"},
)
rust_test(
name = "app_test",
srcs = ["main.rs"],
rustc_env = {"KIND": "test"},
)
main.rs:
pub fn value() -> u8 {
1
}
fn main() {
let _ = value();
}
#[cfg(test)]
mod tests {
#[test]
fn value_is_one() {
assert_eq!(super::value(), 1);
}
}
First verify the targets themselves build/test successfully:
bazel test //:app_test
bazel build //:app
Generate rust-project.json:
bazel run @rules_rust//tools/rust_analyzer:gen_rust_project -- //:app //:app_test
Inspect the crates generated for main.rs:
jq '[.crates[] | select(.root_module | endswith("/main.rs"))] | {matching_crate_count: length, crates: [.[] | {display_name, env_KIND: .env.KIND, cargo_crate_name: .env.CARGO_CRATE_NAME, build_label: .build.label, build_target_kind: .build.target_kind}]}' rust-project.json
Actual output from the repro:
{
"matching_crate_count": 1,
"crates": [
{
"display_name": "app",
"env_KIND": "test",
"cargo_crate_name": "app_test",
"build_label": "//:app_test",
"build_target_kind": "bin"
}
]
}
Expected output:
There should be two distinct crate entries for main.rs: one for //:app with KIND = "binary", and one for //:app_test with KIND = "test".
Additional context
This appears to be caused by consolidate_crate_specs using spec.crate_id alone as the identity key for consolidation.
The existing merge behavior is useful for rust_test(crate = ":lib"), where the test and library share a root module and should be merged so rust-analyzer test code lenses work. The problem is that same crate_id does not always mean same logical rust-analyzer crate.
The same identity issue can also affect target-specific crate variants when the same crate root appears under multiple target triples/configurations. A fix likely needs to distinguish intentional library/test consolidation from unrelated same-root crates and avoid collapsing target-specific variants into one crate.
Related but distinct issues:
Impact
This can make rust-analyzer use incorrect crate metadata. In practice this can cause wrong runnables/code lenses, wrong build labels, wrong environment variables, wrong dependency/alias metadata, or incorrect target-specific analysis.
The workaround is to carry a local patch that qualifies crate IDs before consolidation for distinct same-root binary/test crates and for non-proc-macro crates appearing under multiple target triples.
Bazel and rules_rust version
Reproduced with:
- Bazel:
9.1.1
- rules_rust:
0.71.3 from Bzlmod
- Also reproduced against upstream
bazelbuild/rules_rust main at 46d67bc1fda4592dab7465c8152d94ae6f969cfc
This issue was created with AI assistance and has been human reviewed for accuracy before filing.
Description
rust-project.jsongeneration can merge distinct Rust crates that happen to share the samecrate_id.The current consolidation logic in
tools/rust_analyzer/aquery.rs::consolidate_crate_specsuses onlyCrateSpec.crate_idas the map key.crate_idis derived from the crate root module path, so sharing it is intentional for some cases, such asrust_test(crate = ":lib"). However, the samecrate_idcan also occur for crates that should remain distinct.Current wrong behavior:
A standalone
rust_binaryandrust_testusing the same root file are consolidated into one rust-analyzer crate. The resulting crate can contain mixed metadata from both targets. In the repro below, the generated crate hasdisplay_name = "app", butenv.KIND = "test",env.CARGO_CRATE_NAME = "app_test", andbuild.label = "//:app_test".Expected behavior:
rust-project.jsonshould only merge crate specs when they represent the same logical rust-analyzer crate, such as the existingrust_test(crate = ":lib")case. Distinct same-root standalone binary/test crates should remain separate entries.Reproduction steps
Create a minimal workspace using upstream, unpatched
rules_rust.MODULE.bazel:BUILD.bazel:main.rs:First verify the targets themselves build/test successfully:
bazel test //:app_test bazel build //:appGenerate
rust-project.json:Inspect the crates generated for
main.rs:jq '[.crates[] | select(.root_module | endswith("/main.rs"))] | {matching_crate_count: length, crates: [.[] | {display_name, env_KIND: .env.KIND, cargo_crate_name: .env.CARGO_CRATE_NAME, build_label: .build.label, build_target_kind: .build.target_kind}]}' rust-project.jsonActual output from the repro:
{ "matching_crate_count": 1, "crates": [ { "display_name": "app", "env_KIND": "test", "cargo_crate_name": "app_test", "build_label": "//:app_test", "build_target_kind": "bin" } ] }Expected output:
There should be two distinct crate entries for
main.rs: one for//:appwithKIND = "binary", and one for//:app_testwithKIND = "test".Additional context
This appears to be caused by
consolidate_crate_specsusingspec.crate_idalone as the identity key for consolidation.The existing merge behavior is useful for
rust_test(crate = ":lib"), where the test and library share a root module and should be merged so rust-analyzer test code lenses work. The problem is that samecrate_iddoes not always mean same logical rust-analyzer crate.The same identity issue can also affect target-specific crate variants when the same crate root appears under multiple target triples/configurations. A fix likely needs to distinguish intentional library/test consolidation from unrelated same-root crates and avoid collapsing target-specific variants into one crate.
Related but distinct issues:
Impact
This can make rust-analyzer use incorrect crate metadata. In practice this can cause wrong runnables/code lenses, wrong build labels, wrong environment variables, wrong dependency/alias metadata, or incorrect target-specific analysis.
The workaround is to carry a local patch that qualifies crate IDs before consolidation for distinct same-root binary/test crates and for non-proc-macro crates appearing under multiple target triples.
Bazel and rules_rust version
Reproduced with:
9.1.10.71.3from Bzlmodbazelbuild/rules_rustmainat46d67bc1fda4592dab7465c8152d94ae6f969cfc