Skip to content

Conversation

@J3m3
Copy link
Contributor

@J3m3 J3m3 commented Dec 16, 2025

Since the commit 5038446
("Rewrite method resolution to follow rustc more closely"), the method resolution logic has changed: rust-analyzer only looks up inherent methods for primitive types in sysroot crates.

Unfortunately, this change broke at least one project that relies on rust-project.json: Rust-for-Linux. Its auto-generated rust-project.json directly embeds core, alloc, and std in the crates list without defining sysroot_src. Consequently, rust-analyzer fails to identify them as sysroot crates, breaking IDE support for primitive methods (e.g., 0_i32.rotate_left(0)).

However, specifying sysroot_src creates a new issue: it implicitly adds std as a dependency to all kernel module crates, which are actually compiled with -Zcrate-attr=no_std. Since rust-analyzer cannot see compiler flags passed outside of the project definition, we need a method to explicitly specify #![no_std] or, more generally, crate-level attributes through the project configuration.

To resolve this, extend the rust-project.json format with a new crate_attrs field. This allows users to specify crate-level attributes such as #![no_std] directly into the configuration, enabling rust-analyzer to respect them when analyzing crates.

References:

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 16, 2025
@J3m3
Copy link
Contributor Author

J3m3 commented Dec 16, 2025

I deliberately excluded lint attribute support in this PR, since it would involve a change to the public API. It might deserve a dedicated PR for discussion, since I'm not yet sure it's worth pursuing. Please let me know if anyone thinks this is the better place for it.

@ChayimFriedman2
Copy link
Contributor

We don't hesitate too much before breaking our public API (it's explicitly not stable), especially an API like that that is basically directly intended at its single consumer.

@J3m3
Copy link
Contributor Author

J3m3 commented Dec 16, 2025

We don't hesitate too much before breaking our public API (it's explicitly not stable), especially an API like that that is basically directly intended at its single consumer.

I see, thanks! Then I'll add it here.

Since the commit 5038446
("Rewrite method resolution to follow rustc more closely"), the method
resolution logic has changed: rust-analyzer only looks up inherent
methods for primitive types in sysroot crates.

Unfortunately, this change broke at least one project that relies on
`rust-project.json`: Rust-for-Linux. Its auto-generated
`rust-project.json` directly embeds `core`, `alloc`, and `std` in the
`crates` list without defining `sysroot_src`. Consequently,
rust-analyzer fails to identify them as sysroot crates, breaking IDE
support for primitive methods (e.g., `0_i32.rotate_left(0)`).

However, specifying `sysroot_src` creates a new issue: it implicitly
adds `std` as a dependency to all kernel module crates, which are
actually compiled with `-Zcrate-attr=no_std`. Since rust-analyzer cannot
see compiler flags passed outside of the project definition, we need a
method to explicitly specify `#![no_std]` or, more generally,
crate-level attributes through the project configuration.

To resolve this, extend the `rust-project.json` format with a new
`crate_attrs` field. This allows users to specify crate-level attributes
such as `#![no_std]` directly into the configuration, enabling
rust-analyzer to respect them when analyzing crates.

References:
- The original Zulip discussion:
  https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Primitive.20type.20inherent.20method.20lookup.20fails/with/562983853
Copy link
Contributor

@ChayimFriedman2 ChayimFriedman2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments.

Copy link
Contributor

@ChayimFriedman2 ChayimFriedman2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one nit, then LGTM.

#![cfg(false)] // Crate-level attributes are collected up to here.
#![features(f16,f128)]
#![crate_type = "bin"]
"#;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this doesn't test well that only the chosen attributes are collected. Instead assert that the item tree pretty-printed is equal to the collected attributes. Same for the following test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the result would just look like the below:

#[test]
fn crate_attrs_with_disabled_cfg_injected() {
    check(
        r#"
//- /main.rs crate:foo crate-attr:no_std crate-attr:cfg(false) crate-attr:features(f16,f128) crate-attr:crate_type="bin"
        "#,
        expect![[r#"
            #[cfg(false)]
        "#]]
    );
}

This is because the pretty-print short-circuits when it sees AttrsOrCfg::CfgDisabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already managed to fix this by the way, though I think it isn't perfect for now... let me re-check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can change it to print the attributes before :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can change it to print the attributes before :)

Sorry, but could you elaborate?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine if you don't want to, but the code is at

let AttrsOrCfg::Enabled { attrs } = attrs else {
and can be changed to also print the attributes (then #[cfg(false)], or even #[cfg(cfg_expr)] if you feel brave).

Copy link
Contributor Author

@J3m3 J3m3 Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done implementing including #[cfg(cfg_expr)] printing. Would you like this to be a separate PR? I think this has a user-visible impact on "Feature: Debug ItemTree".

pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String {
let sema = Semantics::new(db);
let file_id = sema.attach_first_edition(file_id);
db.file_item_tree(file_id.into()).pretty_print(db, file_id.edition(db))
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatever you prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants