| #![warn(clippy::needless_borrows_for_generic_args)] |
| #![allow( |
| clippy::unnecessary_to_owned, |
| clippy::unnecessary_literal_unwrap, |
| clippy::needless_borrow |
| )] |
| |
| use core::ops::Deref; |
| use std::any::Any; |
| use std::ffi::OsStr; |
| use std::fmt::{Debug, Display}; |
| use std::path::Path; |
| use std::process::Command; |
| |
| fn main() { |
| let _ = Command::new("ls").args(["-a", "-l"]).status().unwrap(); |
| let _ = Path::new(".").join("."); |
| let _ = Any::type_id(&""); // Don't lint. `Any` is only bound |
| let _ = Box::new(&""); // Don't lint. Type parameter appears in return type |
| let _ = Some("").unwrap_or(&""); |
| let _ = std::fs::write("x", "".to_string()); |
| |
| { |
| #[derive(Clone, Copy)] |
| struct X; |
| |
| impl Deref for X { |
| type Target = X; |
| fn deref(&self) -> &Self::Target { |
| self |
| } |
| } |
| |
| fn deref_target_is_x<T: Deref<Target = X>>(_: T) {} |
| |
| deref_target_is_x(X); |
| } |
| { |
| fn multiple_constraints<T, U, V, X, Y>(_: T) |
| where |
| T: IntoIterator<Item = U> + IntoIterator<Item = X>, |
| U: IntoIterator<Item = V>, |
| V: AsRef<str>, |
| X: IntoIterator<Item = Y>, |
| Y: AsRef<OsStr>, |
| { |
| } |
| |
| multiple_constraints([[""]]); |
| } |
| { |
| #[derive(Clone, Copy)] |
| struct X; |
| |
| impl Deref for X { |
| type Target = X; |
| fn deref(&self) -> &Self::Target { |
| self |
| } |
| } |
| |
| fn multiple_constraints_normalizes_to_same<T, U, V>(_: T, _: V) |
| where |
| T: Deref<Target = U>, |
| U: Deref<Target = V>, |
| { |
| } |
| |
| multiple_constraints_normalizes_to_same(X, X); |
| } |
| { |
| fn only_sized<T>(_: T) {} |
| only_sized(&""); // Don't lint. `Sized` is only bound |
| } |
| { |
| fn ref_as_ref_path<T: 'static>(_: &'static T) |
| where |
| &'static T: AsRef<Path>, |
| { |
| } |
| |
| ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter |
| } |
| { |
| trait RefsOnly { |
| type Referent; |
| } |
| |
| impl<T> RefsOnly for &T { |
| type Referent = T; |
| } |
| |
| fn refs_only<T, U>(_: T) |
| where |
| T: RefsOnly<Referent = U>, |
| { |
| } |
| |
| refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't |
| } |
| { |
| fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U) |
| where |
| T: IntoIterator<Item = U>, |
| U: IntoIterator<Item = V>, |
| V: AsRef<str>, |
| { |
| } |
| multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments |
| } |
| // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 |
| { |
| #[derive(Clone, Copy)] |
| struct Iter; |
| impl Iterator for Iter { |
| type Item = (); |
| fn next(&mut self) -> Option<Self::Item> { |
| None |
| } |
| } |
| fn takes_iter(_: impl Iterator) {} |
| fn dont_warn(mut x: Iter) { |
| takes_iter(&mut x); |
| } |
| #[allow(unused_mut)] |
| fn warn(mut x: &mut Iter) { |
| takes_iter(x) |
| } |
| } |
| #[clippy::msrv = "1.52.0"] |
| { |
| let _ = Command::new("ls").args(&["-a", "-l"]).status().unwrap(); |
| }; |
| #[clippy::msrv = "1.53.0"] |
| { |
| let _ = Command::new("ls").args(["-a", "-l"]).status().unwrap(); |
| }; |
| { |
| let env = "env".to_owned(); |
| let arg = "arg".to_owned(); |
| let f = |arg| { |
| let loc = "loc".to_owned(); |
| let _ = std::fs::write("x", &env); // Don't lint. In environment |
| let _ = std::fs::write("x", &arg); |
| let _ = std::fs::write("x", &loc); |
| }; |
| let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f` |
| f(arg); |
| } |
| { |
| #[derive(Debug)] |
| struct X; |
| |
| impl Drop for X { |
| fn drop(&mut self) {} |
| } |
| |
| fn f(_: impl Debug) {} |
| |
| let x = X; |
| f(&x); // Don't lint, not copy, passed by a reference to a variable |
| } |
| { |
| fn f(_: impl AsRef<str>) {} |
| |
| let x = String::new(); |
| f(&x); |
| } |
| { |
| fn f(_: impl AsRef<str>) {} |
| fn f2(_: impl AsRef<str>) {} |
| |
| let x = String::new(); |
| f(&x); |
| f2(&x); |
| } |
| // https://github.com/rust-lang/rust-clippy/issues/9111#issuecomment-1277114280 |
| // issue 9111 |
| { |
| struct A; |
| |
| impl Extend<u8> for A { |
| fn extend<T: IntoIterator<Item = u8>>(&mut self, _: T) { |
| unimplemented!() |
| } |
| } |
| |
| impl<'a> Extend<&'a u8> for A { |
| fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, _: T) { |
| unimplemented!() |
| } |
| } |
| |
| let mut a = A; |
| a.extend(&[]); // vs a.extend([]); |
| } |
| // issue 9710 |
| { |
| fn f(_: impl AsRef<str>) {} |
| |
| let x = String::new(); |
| for _ in 0..10 { |
| f(&x); |
| } |
| } |
| // issue 9739 |
| { |
| fn foo<D: Display>(_it: impl IntoIterator<Item = D>) {} |
| foo(if std::env::var_os("HI").is_some() { |
| &[0] |
| } else { |
| &[] as &[u32] |
| }); |
| } |
| { |
| struct S; |
| |
| impl S { |
| fn foo<D: Display>(&self, _it: impl IntoIterator<Item = D>) {} |
| } |
| |
| S.foo(if std::env::var_os("HI").is_some() { |
| &[0] |
| } else { |
| &[] as &[u32] |
| }); |
| } |
| // issue 9782 |
| { |
| fn foo<T: AsRef<[u8]>>(t: T) { |
| println!("{}", std::mem::size_of::<T>()); |
| let _t: &[u8] = t.as_ref(); |
| } |
| |
| let a: [u8; 100] = [0u8; 100]; |
| |
| // 100 |
| foo::<[u8; 100]>(a); |
| foo(a); |
| |
| // 16 |
| foo::<&[u8]>(&a); |
| foo(a.as_slice()); |
| |
| // 8 |
| foo::<&[u8; 100]>(&a); |
| foo(a); |
| } |
| { |
| struct S; |
| |
| impl S { |
| fn foo<T: AsRef<[u8]>>(t: T) { |
| println!("{}", std::mem::size_of::<T>()); |
| let _t: &[u8] = t.as_ref(); |
| } |
| } |
| |
| let a: [u8; 100] = [0u8; 100]; |
| S::foo::<&[u8; 100]>(&a); |
| } |
| { |
| struct S; |
| |
| impl S { |
| fn foo<T: AsRef<[u8]>>(&self, t: T) { |
| println!("{}", std::mem::size_of::<T>()); |
| let _t: &[u8] = t.as_ref(); |
| } |
| } |
| |
| let a: [u8; 100] = [0u8; 100]; |
| S.foo::<&[u8; 100]>(&a); |
| } |
| // issue 10535 |
| { |
| static SOME_STATIC: String = String::new(); |
| |
| static UNIT: () = compute(&SOME_STATIC); |
| |
| pub const fn compute<T>(_: T) |
| where |
| T: Copy, |
| { |
| } |
| } |
| // address of field when operand impl Drop |
| { |
| struct CustomDrop(String); |
| |
| impl Drop for CustomDrop { |
| fn drop(&mut self) {} |
| } |
| |
| fn check_str<P: AsRef<str>>(_to: P) {} |
| |
| fn test() { |
| let owner = CustomDrop(String::default()); |
| check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop |
| } |
| } |
| { |
| #[derive(Debug)] |
| struct X(Vec<u8>); |
| |
| fn f(_: impl Debug) {} |
| |
| let x = X(vec![]); |
| f(&x); // Don't lint, makes x unavailable later |
| } |
| { |
| #[derive(Debug)] |
| struct X; |
| |
| impl Drop for X { |
| fn drop(&mut self) {} |
| } |
| |
| fn f(_: impl Debug) {} |
| |
| #[derive(Debug)] |
| struct Y(X); |
| |
| let y = Y(X); |
| f(&y); // Don't lint. Not copy, passed by a reference to value |
| } |
| { |
| fn f(_: impl AsRef<str>) {} |
| let x = String::new(); |
| f(&x); // Don't lint, not a copy, makes it unavailable later |
| f(String::new()); // Lint, makes no difference |
| let y = "".to_owned(); |
| f(&y); // Don't lint |
| f("".to_owned()); // Lint |
| } |
| } |