lazy-static.rs icon indicating copy to clipboard operation
lazy-static.rs copied to clipboard

Unable to provide a Clippy suppression attribute for a variable's type

Open yeputons opened this issue 2 years ago • 1 comments

Consider the following example:

use http::Uri;
use std::collections::HashSet;
use lazy_static::lazy_static;

fn main() {
    // Clippy thinks that `Uri` has interior mutability and yields a warning
    let _a: HashSet<Uri> = HashSet::new();
    // Warning is suppressed
    #[allow(clippy::mutable_key_type)]
    let _b: HashSet<Uri> = HashSet::new();
}

lazy_static! {
    // Trying to suppress the warning
    #[allow(clippy::mutable_key_type)]
    static ref _C: HashSet<Uri> = HashSet::new();
}

if I run clippy on it, I get:

    Checking playground v0.0.1 (/playground)
warning: mutable key type
 --> src/main.rs:7:5
  |
7 |     let _a: HashSet<Uri> = HashSet::new();
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(clippy::mutable_key_type)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type

warning: mutable key type
  --> src/main.rs:16:20
   |
16 |     static ref _C: HashSet<Uri> = HashSet::new();
   |                    ^^^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type

warning: mutable key type
  --> src/main.rs:13:1
   |
13 | / lazy_static! {
14 | |     // Trying to suppress the warning
15 | |     #[allow(clippy::mutable_key_type)]
16 | |     static ref _C: HashSet<Uri> = HashSet::new();
17 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
   = note: this warning originates in the macro `__lazy_static_internal` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: `playground` (bin "playground") generated 3 warnings
    Finished dev [unoptimized + debuginfo] target(s) in 0.43s

So, the warning is not suppressed on _a and is suppressed on _b as expected. However, the attribute on _C does nothing. Moreover, two warnings are yielded, not just one.

Looking at the expansion (courtesy of IntelliJ's Rust plugin, so may be off):

#[allow(missing_copy_implementations)]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(clippy::mutable_key_type)]
struct _C {
    __private_field: (),
}
#[doc(hidden)]
static _C: _C = _C { __private_field: () };
impl ::lazy_static::__Deref for _C {
    type Target = HashSet<Uri>;
    fn deref(&self) -> &HashSet<Uri> {
        #[inline(always)]
        fn __static_ref_initialize() -> HashSet<Uri> { (HashSet::new()) }

        #[inline(always)]
        fn __stability() -> &'static HashSet<Uri> {
            static LAZY: ::lazy_static::lazy::Lazy<HashSet<Uri>> = ::lazy_static::lazy::Lazy::INIT;
            LAZY.get(__static_ref_initialize)
        }
        __stability()
    }
}
impl ::lazy_static::LazyStatic for _C {
    fn initialize(lazy: &Self) {
        let _ = &**lazy;
    }
}

It seems that the attribute is attached to the struct _C, but warnings are actually emitted by some code in the macro. I'm not really sure what is the proper fix here: I suspect some attribute should really go to the struct _C, some should go to the static _C, and some (like allow(clippy::mutable_key_type) should be scattered in the macro.

yeputons avatar Jun 01 '22 20:06 yeputons