[WIP] Add flag to warn about unused dependencies#8437
[WIP] Add flag to warn about unused dependencies#8437est31 wants to merge 4 commits intorust-lang:masterfrom
Conversation
|
r? @ehuss (rust_highfive has picked a reviewer for you, use r? to override) |
bfa9e29 to
3fa84f7
Compare
8052e20 to
6133918
Compare
|
This is a table of some commands and what they actually compile/check:
So practically in almost every instance cargo can't warn about dev-dependencies without making false positives possible. |
1ae02d1 to
f5f2c81
Compare
|
If cargo can't support dependency warnings as a side effect of normal builds, does dependency checking need to be its own explicit operation? Eg |
|
@jsgf in fact I think a command that compiles every part of a crate would be useful even outside of the unused dependencies scenario, to ensure that no code is breaking the build. Currently there is no such command. But I think that should better be discussed separately from this PR, as the PR implements checks for normal and build dependencies as well, and those checks are both more helpful (people depending on your crate don't compile your dev deps, only the normal and build deps), as well as more easily triggered (cargo build/check/test without any params all trigger the warnings). A rejection of such a mode, or any technical difficulties with implementing it shouldn't slow down the introduction of warnings for normal and build deps. |
|
This is a pretty slick way to detect unused dependencies, thanks for prototyping this! One thing I figured I'd comment on is that warnings is one thing Cargo has historically not handled well. Generally with warnings you want the ability to do something like "turn them all to errors" or "allow them for this project or temporarily". This is handled really well in the compiler with More concretely, I think that new warnings could fall short in a few situations:
Since this is being developed in tandem with rustc I think it would be great to basically just figure out how to get rustc to emit these warnings one way or another. Either that or let rustc make all the decisions about whether Cargo should be allowing or denying warnings. Or... something along those lines, I don't know of a great solution myself, but I wanted to at least write this up since I think it will be important to get right. |
Yeah, before the feature is stabilized and enabled by default there should be a way to turn off the warnings at least. I'm not certain myself how it should look like so I thought it should be done after the PR but we can already discuss it now.
There's already support for this in the PR! It works just like _bar = { package = "bar", version = "0.1.0" }But there is also a way to do it from Rust code via
In fact this has already been implemented for buck use cases in rust-lang/rust#72342 , but for cargo it is not suiting, as cargo doesn't have a 1:1 correspondence between dependencies and compilation units. In order to detect that an entry in the
rustc would have to tell this info to cargo in some way so that cargo could unify the output from multiple units and tell the result. I could add info on whether to allow, deny, or warn to the json output communicated by rustc. |
|
☔ The latest upstream changes (presumably #8427) made this pull request unmergeable. Please resolve the merge conflicts. |
|
One idea we had for warning control in yesterday's Cargo meeting is that rustc could emit warnings/errors for unused crates (e.g. unused This strategy would require Cargo to be able to identify lints precisely for unused crates (it's either already in the JSON structure or presumably we could add it). It would also require the addition of a "non fatal error" in rustc where if the lint is Unifying this across many crates would look something like:
That will require more changes in rustc for sure, but it seems quite appealing in terms of being able to control lint levels in Cargo. |
|
@alexcrichton if I have this code: fn hello() {
}
mod foo {
}
mod bar {
}Then why should a Also see the PR description of rust-lang/rust#73945 for further issues with that approach under the "Why not pass -Wunused-crate-dependencies?" section. For controlling lint levels, I think that cargo should think about ways of allowing/denying lints for all units in a crate or even workspace, as that's usually what people want when they control lints in their crate lib.rs root (#5034). Control over the unused dependencies lint could build on that. Depending on the name, if it starts with |
|
We explicitly are trying to avoid a system of managing lints in Cargo. It's not perfect to use rustc for this, but IMO it's way better than inventing something entirely new for Cargo. |
Who is "we" in that sentence? You? The entire cargo team? Most of the complexity of a "lints for cargo" system would already be covered by #5034 , so not really be a cost introduced by the unused dependencies lint.
It would make the unused dependencies lint different from all other lints. Furthermore, cargo wouldn't just always re-emit that warning/error unchanged if it wants to support "this should rather be a dev-dependency" or (in the future) "this should rather be a bin-dependency" like messages (wich this PR already does). So the entire distinction between warning/error/etc would have to be supported by cargo. Another issue would be that it would make doctests more complicated. Rustdoc has to collect the reports of all doc snippets and combine them. The more simple the format is, the easier this combination. It also offloads a lot of the ugly hacks to rustc so not sure whether the rustc team will support that (or the rustdoc team). THAT being said, if all three teams are aware of what the proposal entails and okay with that, I'm ok with it as well. |
|
The "we" is the Cargo team. If you'd like to block this on #5034 that's your choice, but AFAIK there are no plans to implement that. What I mentioned was a suggestion, if you don't want to pursue it, that's ok. The Cargo team's requirements have been laid out here and we're offering one way to do it, but if you'd rather do something else that checks the boxes that should work too. |
|
Sounds fair! I'll think a bit about other approaches that satisfy the demands of the cargo team. Note though that I won't have that much time to work on it in the next few months. The next thing I'll focus on will probably be json output for rustdoc errors. The mode will be required for implementation methods. |
|
The companion PR has been merged, so I believe this is no longer blocked! |
|
@camelid I'll rebase the PR soon! |
This refactors the drain_the_queue function to return a tuple containing Result. That way, it's still not possible to use ? or try! to handle errors, but for readers of the function declaration it's clearer now that the error actually indicates one. Bonus: it makes the calling code of drain_the_queue simpler.
This commit adds an experimental flag to cargo, -Zwarn-unused-deps,
with the goal of getting it eventually stabilized and enabled by
default.
The lint builds upon the --json=unused-externs flag of rustc
that is being proposed for this purpose.
This commit makes cargo pass the flag if -Zwarn-unused-deps is enabled
to compilations of units it prints warnings for.
During compilation, code collects the unused dependencies
from all units, converts them into used dependencies,
continuously extending the record of used dependencies for
any type of DepKind: [dependencies], [dev-dependencies] and
[build-dependencies].
Once the compilation has ended, this record is used to
obtain those dependencies in a class that weren't used by any unit,
and warn about them.
The goal is to stabilize the flag and enable it by default
once the lint has become robust and the robustness is proven.
Then, cargo shall opportunistically warn about unused dependencies
when it has compiled (or loaded the unused externs from cache of)
all units that could possibly use dependencies of the kind.
Roughly, it's like this:
* cargo always compiles build.rs
* cargo check compiles all units that would use [dependencies]
* cargo test --no-run --all-targets compiles all units that can use
[dev-dependencies]... except for the benches
* cargo check --all-targets compiles all units that can use
[dev-dependencies]... except for the doctests
Specifying via the command line is not possible for now because cargo currently has to pass -W via the command line, but once the lint is set to warn by default, this won't be needed :).
|
☔ The latest upstream changes (presumably #9369) made this pull request unmergeable. Please resolve the merge conflicts. |
|
I'm gonna close this due to inactivity. Feel free to reopen or create a new PR when you've got time to work on this again. Thanks! |
|
The main blocker at this point is having a line with only "yes" inside in this table: #8437 (comment) |
|
From July 23, 2020
but nonethless, a few years later, Cargo was given a system of managing lints: RFC 3389 was implemented via tracking-issue #12115, to add a |
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
Fixes rust-lang#15813 Built-on rust-lang#8437 This does nothing for dev-dependencies because there isn't really a way to select all targets today without - tracking selected dep kinds to check on a per-package basis - checking the status of every bench to see if it can work as a test because `cargo test` (no args) with benches set to test is the only command today that can exercise all dev-dependencies as it is the only one that will compile tests and doctests. See also - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#detecting-unused-dependencies - https://blog.rust-lang.org/inside-rust/2024/10/01/this-development-cycle-in-cargo-1.82/#all-targets-and-doc-tests - https://blog.rust-lang.org/inside-rust/2024/10/31/this-development-cycle-in-cargo-1.83/#target-and-target
This commit adds an experimental flag to cargo, -Zwarn-unused-deps.
If the flag is enabled, cargo will warn about unused dependencies. rustc issue for the feature: rust-lang/rust#57274
The goal is to stabilize it eventually, enabling it by default.
The lint builds upon the --json=unused-externs flag of rustc
that is being proposed for this purpose in the companion PR rust-lang/rust#73945 .
This PR makes cargo pass the flag if -Zwarn-unused-deps is enabled to compilations of units it prints warnings for.
During compilation, cargo collects the unused dependencies
from all units, converts them into used dependencies,
continuously extending the record of used dependencies for
any type of DepKind: [dependencies], [dev-dependencies] and
[build-dependencies].
Once the compilation has ended, this record is used to
obtain those dependencies in a class that weren't used by any unit,
and warn about them.
The goal is to stabilize the flag and enable it by default
once the lint has become robust and the robustness is proven.
Then, cargo shall opportunistically warn about unused dependencies
when it has compiled (or loaded the unused externs from cache of)
all units that could possibly use dependencies of the kind.
Roughly, it's like this:
[dev-dependencies]
TODO
The PR is still WIP but I've opened it to get initial feedback. TODO list:
#[cfg(test)] use extern_crate as _;cc @ehuss @jsgf