rust-lang / rust-lang/rust-clippy
`clippy::manual_unwrap_or_default` triggers on macro generated code
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
Summary
With nightly I have some errors like this in my macro generated code, which can not be easily silenced.
warning: if let can be simplified with `.unwrap_or_default()`
--> serde_with_macros/src/utils.rs:36:33
|
36 | #[darling(rename = "crate", default)]
| ^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or_default
= note: `#[warn(clippy::manual_unwrap_or_default)]` on by default
help: replace it with
|
36 ~ #[darling(rename = "crate", default)]
37 ~ pub(crate) alt_crate_path.unwrap_or_default())]
|
Lint Name
clippy::manual_unwrap_or_default
Reproducer
I tried this code:
#[derive(FromDeriveInput)]
#[darling(attributes(serde_with))]
pub(crate) struct DeriveOptions {
/// Path to the crate
#[darling(rename = "crate", default)]
pub(crate) alt_crate_path: Option<Path>,
}
I saw this happen:
warning: if let can be simplified with `.unwrap_or_default()`
--> serde_with_macros/src/utils.rs:36:33
|
36 | #[darling(rename = "crate", default)]
| ^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or_default
= note: `#[warn(clippy::manual_unwrap_or_default)]` on by default
help: replace it with
|
36 ~ #[darling(rename = "crate", default)]
37 ~ pub(crate) alt_crate_path.unwrap_or_default())]
|
I expected to see this happen:
No warnings should be caused by the generated code.
The derive macro that generates the Default::default() code looks like this:
impl<'a> ToTokens for DefaultExpression<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.append_all(match *self {
DefaultExpression::Inherit(ident) => {
let dsn = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site());
quote!(#dsn.#ident)
}
DefaultExpression::Explicit(path) => {
// Use quote_spanned to properly set the span of the parentheses
quote_spanned!(path.span()=>#path())
}
DefaultExpression::Trait { span } => {
quote_spanned!(span=> ::darling::export::Default::default())
}
});
}
}
This looks like a reasonable implementation to me. Replacing the Default::default() with unwrap_or_default is not trivially done. It selects the correct code to generate a default value, based on an explicitly given path or implicitly using Default. The darling(default) works very similar to serde(default). The generated code does emit the #[automatically_derived] attribute.
Version
rustc 1.79.0-nightly (aa1c45908 2024-04-06)
binary: rustc
commit-hash: aa1c45908df252a5b0c14e1bcb38c6c55ae02efe
commit-date: 2024-04-06
host: x86_64-unknown-linux-gnu
release: 1.79.0-nightly
LLVM version: 18.1.2
Additional Labels
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the manual_unwrap_or_default lint implementation and run the supplied serde_with_macros/src/utils.rs reproducer. Trace how the lint handles spans from macro-generated code and the #[automatically_derived] attribute; done means the reproducer emits no warning while ordinary applicable code remains diagnosed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100