Check for obsolete clippy allowances - rust

Sometimes you want to suppress a clippy warning for the time being and you let clippy ignore a specific rule for a specific code block by adding lines like the following:
#[allow(dead_code)]
But as the project continues, it can actually happen that you remove the problem, without actually removing the allowing of the clippy lint. So is there a way to check for allowed clippy warnings that are actually not being used anymore? So in this example I'd like to be informed when I #[allow(dead_code)] but there is actually no dead code to be found in the given code block.

The unstable feature (currently only usable using the nightly Rust compiler) lint_reasons includes the ability to use expect( instead of allow(, which allows the lint but warns if the lint is not detected.
#![feature(lint_reasons)]
#[expect(dead_code)]
fn foo() {}
fn main() {
foo();
}
Output:
warning: this lint expectation is unfulfilled
--> src/main.rs:3:10
|
3 | #[expect(dead_code)]
| ^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
There is no current schedule for this to make it to stable but at least people want to see it and there's an implementation.

You could try prefixing unused functions/variables/etc. with a _ (the compiler will also mention this.) if you do not want the warnings to appear. If you remove the any of the temporary/dead code containing the prefix, you won't have to worry about #![allow(dead_code)].

Related

Is there a warning for undocumented sections?

I am writing a crate that I plan to publish. When publishing, one of the most important thing (in my opinion) is to ensure the crate is well documented. Therefore my question : is there a warning to be turned on which warms undocumented sections of the code ?
E.g.: I typically think of something like #[warn(undocumented)].
Yes, such a lint exists. The rustc compiler provides the missing_docs lint, which warns about missing documentation on public items when enabled. The clippy linter provides the missing_docs_in_private_items lint, which additionally warns… well, you guessed it. Note that missing_docs_in_private_items warns for all items, so you don't need missing_docs if you enable it.
You can enable the lints using
#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
for warnings or
#![deny(missing_docs)]
#![deny(clippy::missing_docs_in_private_items)]
for errors.
You are looking for the missing-docs lint in the Rust compiler.
Example:
#![warn(missing_docs)]
fn foo(bar: i32) {}
The output from the compiler:
warning: missing documentation for crate
--> src/lib.rs:1:1
|
1 | / #![warn(missing_docs)]
2 | |
3 | | fn foo(bar: i32) {}
| |___________________^
|
You may also find more lints in the rustc book.

How can I retrieve the full path of a trait bound in a Rust compiler plugin?

I'm working on a Rust plugin that needs to access the absolute path of a trait bound. In practice, this means that for the following code, I want to resolve the full path of Debug as std::fmt::Debug.
use std::fmt::*;
#[foo]
trait Foo: Debug {}
My current approach consist of taking the Annotatable that MultiItemDecorator provides for me and pattern matching it to
Annotatable::Item, where I match .node to ItemKind::Trait. I then match .generic_bounds to a collection of GenericBound::Trait, where I retrieve .trait_ref.path.
This struct however only contains path(Debug), which is not enough information for me.
You can't.
The Rustc Driver:
[…] the main phases of the compiler are:
Parse Input: Initial crate parsing
Configure and Expand: Resolve #[cfg] attributes, name resolution, and expand macros
Run Analysis Passes: Run trait resolution, typechecking, region checking and other miscellaneous analysis passes on the crate
Translate to LLVM: Translate to the in-memory form of LLVM IR and turn it into an executable/object files
(emphasis is mine)
Macros are expanded before trait resolution is done, so at the time your plugin is run, nothing is known about this Debug except the name given in the source code.

"cargo check" gives dead code warning for function used only by test [duplicate]

I'm writing a program in Rust and I have some tests for it. I wrote a helper function for these tests, but whenever I build using cargo build it warns me that the function is never used:
warning: function is never used: ... #[warn(dead_code)] on by default
How I can mark this function as used so as not to get the warnings?
Specific question
How I can mark this function as used so as not to get the warnings?
The Rust compiler runs many lints to warn you about possible issues in your code and the dead_code lint is one of them. It can be very useful in pointing out mistakes when code is complete, but may also be a nuisance at earlier stages. Often, this can be solved by either deleting unused code, or by marking a public method. However, all lints can be turned off by allowing them, and your error message (#[warn(dead_code)] on by default) contains the name of the lint you could disable.
#[allow(dead_code)]
fn my_unused_function() {}
Alternative for testing
I wrote a helper function for these tests, but whenever I build using cargo build it warns me that the function is never used.
This happens to be a special case, which is that code that is only used for testing isn't needed in the real executable and should probably not be included.
In order to optionally disable compilation of test code, you can mark it accordingly using the cfg attribute with the test profile.
#[cfg(test)]
fn my_test_specific_function() {}
When marked in this way, the compiler knows to ignore the method during compilation. This is similar to commonly used ifdef usage in other languages like C or C++, where you are telling a preprocessor to ignore the enclosed code unless TESTING is defined.
#ifdef TESTING
...
#endif
For people getting this warning while making a rust library, you may get this if you don't have your modules set to pub in your lib.rs.
pub mod foo;
If something is only used in tests, it should be omitted altogether. This can be done with the #[cfg(test)] attribute.
dead_code is a lint, which means you can allow it on the thing that's causing it to trigger.
#[allow(dead_code)]
fn dummy() {}
fn main() {}
There is another situation where this can occur. If you have several helper functions in a module, e.g. in tests/utils/mod.rs and then several integration tests (tests/a.rs, tests/b.rs) each of which does
mod utils;
use utils::...;
then you will get dead code warnings if you do not use all of the code from all of the tests. For example if test a.rs only uses utils::foo and b.rs only uses utils::bar then you will get dead code warnings for both.
That is because each test is compiled as an independent crate. Here is the bug report for it. It looks difficult to solve so I wouldn't hold my breath.
You can disable specific lints for a whole project in Rust by going into your main.rs file and adding the following at the very top of the file:
#![allow(
dead_code,
unused_imports
)]
You max prefix the unused function name with an underscore:
fn _dummy() {}
fn main() {}
See: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#dead-code
For some reason I found that setting the main function to public:
pub fn main()
and then copying my main.rs file to lib.rs
cp src/main.rs src/lib.rs
then recompiling fixed this.
No need to use a macro for it, although the macro should work for non main functions.

How to add code only for specific Rust version without using a build script?

I use a method that appeared in Rust 1.10 for my tests but I want my crate to also work with version 1.7.
Is there a way (something like attribute #[cfg(min_version="1.10")]) to specify code that should only run in Rust 1.10 or newer?
I could use a build script, but I don't want a more complicated build just because I wanted to test my crate on an older Rust version.
While there is no way except build scripts (and in the future procedural macros) to check compiler versions, you can use feature flags to manually enable and disable code.
Usually you want to use some new compiler feature to provide new functionality which you could not do with the old compiler. In that case you use the cfg attribute with feature flags which you define to enable code. E.g.
#[cfg(feature = "foo")]
pub fn foo() {
cool_new_compiler_function();
}
And in your Cargo.toml:
[features]
foo = []
Hiding code behind feature flags like this also works in test code. In your specific case you could alternately introduce a legacy feature and disable tests using modern code like this:
#[test]
#[cfg(not(feature = "legacy"))]
fn test_foo() {
Foo::foo();
}
And then to run tests in legacy mode you run:
cargo test --features "legacy"
Note that doing it the latter way means that your tests will not compile by default on older compilers. For normal (non-test) code, adding such a legacy flag would be a very bad, breaking change.

How to quiet a warning for a single statement in Rust?

Say there is a single warning such as path_statements, unused_variables. Is there a way to ignore a single instant of this, without isolating them into a code block or function?
To be clear, when there is a single warning in the code. I would like the ability to quiet only that warning, without having to do special changes addressing the particular warning.
And without this quieting warnings anywhere else, even later on in the same function.
With GCC this can be done as follows:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
/* Isolated region which doesn't raise warnings! */
this_would_raise_Wformat(args);
#pragma GCC diagnostic pop
Does Rust have the equivalent capability?
Note, am asking about the general case of how to quiet warnings.
Am aware there are ways to resolve unused var warning for eg.
To silence warnings you have to add the allow(warning_type) attribute to the affected expression or any of its parents. If you only want to silence the warning on one specific expression, you can add the attribute to that expression/statement:
fn main() {
#[allow(unused_variables)]
let not_used = 27;
#[allow(path_statements)]
std::io::stdin;
println!("hi!");
}
However, the feature of adding attributes to statements/expressions (as opposed to items, like functions) is still a bit broken. In particular, in the above code, the std::io::stdin line still triggers a warning. You can read the ongoing discussion about this feature here.
Often it is not necessary to use an attribute though. Many warnings (like unused_variables and unused_must_use) can be silenced by using let _ = as the left side of your statement. In general, any variable that starts with an underscore won't trigger unused-warnings.
If you want to silence all warnings of a kind in a module, write e.g. #![allow(dead_code)] (note the exclamation mark) at the top of the module. This will disable all warnings of this kind in the whole module. You can also call rustc with e.g. -A dead_code.
You can disable all warnings by writing #![allow(warnings)] at the top of the module.
You can insert a module (as described in the Rust book) where the specific warnings are ignored.
As Lukas said, you can also write e.g. #[allow(dead_code)] on a statement or an expression.

Resources