| //@run-rustfix |
| |
| #![allow(clippy::needless_borrow, clippy::ptr_arg)] |
| #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] |
| |
| use std::borrow::Cow; |
| use std::ffi::{CStr, CString, OsStr, OsString}; |
| use std::ops::Deref; |
| |
| #[derive(Clone)] |
| struct X(String); |
| |
| impl Deref for X { |
| type Target = [u8]; |
| fn deref(&self) -> &[u8] { |
| self.0.as_bytes() |
| } |
| } |
| |
| impl AsRef<str> for X { |
| fn as_ref(&self) -> &str { |
| self.0.as_str() |
| } |
| } |
| |
| impl ToString for X { |
| fn to_string(&self) -> String { |
| self.0.to_string() |
| } |
| } |
| |
| impl X { |
| fn join(&self, other: impl AsRef<str>) -> Self { |
| let mut s = self.0.clone(); |
| s.push_str(other.as_ref()); |
| Self(s) |
| } |
| } |
| |
| #[allow(dead_code)] |
| #[derive(Clone)] |
| enum FileType { |
| Account, |
| PrivateKey, |
| Certificate, |
| } |
| |
| fn main() { |
| let c_str = CStr::from_bytes_with_nul(&[0]).unwrap(); |
| let os_str = OsStr::new("x"); |
| let path = std::path::Path::new("x"); |
| let s = "x"; |
| let array = ["x"]; |
| let array_ref = &["x"]; |
| let slice = &["x"][..]; |
| let x = X(String::from("x")); |
| let x_ref = &x; |
| |
| require_c_str(&Cow::from(c_str)); |
| require_c_str(c_str); |
| |
| require_os_str(os_str); |
| require_os_str(&Cow::from(os_str)); |
| require_os_str(os_str); |
| |
| require_path(path); |
| require_path(&Cow::from(path)); |
| require_path(path); |
| |
| require_str(s); |
| require_str(&Cow::from(s)); |
| require_str(s); |
| require_str(x_ref.as_ref()); |
| |
| require_slice(slice); |
| require_slice(&Cow::from(slice)); |
| require_slice(array.as_ref()); |
| require_slice(array_ref.as_ref()); |
| require_slice(slice); |
| require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. |
| |
| require_x(&Cow::<X>::Owned(x.clone())); |
| require_x(&x_ref.to_owned()); // No longer flagged because of #8759. |
| |
| require_deref_c_str(c_str); |
| require_deref_os_str(os_str); |
| require_deref_path(path); |
| require_deref_str(s); |
| require_deref_slice(slice); |
| |
| require_impl_deref_c_str(c_str); |
| require_impl_deref_os_str(os_str); |
| require_impl_deref_path(path); |
| require_impl_deref_str(s); |
| require_impl_deref_slice(slice); |
| |
| require_deref_str_slice(s, slice); |
| require_deref_slice_str(slice, s); |
| |
| require_as_ref_c_str(c_str); |
| require_as_ref_os_str(os_str); |
| require_as_ref_path(path); |
| require_as_ref_str(s); |
| require_as_ref_str(&x); |
| require_as_ref_slice(array); |
| require_as_ref_slice(array_ref); |
| require_as_ref_slice(slice); |
| |
| require_impl_as_ref_c_str(c_str); |
| require_impl_as_ref_os_str(os_str); |
| require_impl_as_ref_path(path); |
| require_impl_as_ref_str(s); |
| require_impl_as_ref_str(&x); |
| require_impl_as_ref_slice(array); |
| require_impl_as_ref_slice(array_ref); |
| require_impl_as_ref_slice(slice); |
| |
| require_as_ref_str_slice(s, array); |
| require_as_ref_str_slice(s, array_ref); |
| require_as_ref_str_slice(s, slice); |
| require_as_ref_slice_str(array, s); |
| require_as_ref_slice_str(array_ref, s); |
| require_as_ref_slice_str(slice, s); |
| |
| let _ = x.join(x_ref); |
| |
| let _ = slice.iter().copied(); |
| let _ = slice.iter().copied(); |
| let _ = [std::path::PathBuf::new()][..].iter().cloned(); |
| let _ = [std::path::PathBuf::new()][..].iter().cloned(); |
| |
| let _ = slice.iter().copied(); |
| let _ = slice.iter().copied(); |
| let _ = [std::path::PathBuf::new()][..].iter().cloned(); |
| let _ = [std::path::PathBuf::new()][..].iter().cloned(); |
| |
| let _ = check_files(&[FileType::Account]); |
| |
| // negative tests |
| require_string(&s.to_string()); |
| require_string(&Cow::from(s).into_owned()); |
| require_string(&s.to_owned()); |
| require_string(&x_ref.to_string()); |
| |
| // `X` isn't copy. |
| require_slice(&x.to_owned()); |
| require_deref_slice(x.to_owned()); |
| |
| // The following should be flagged by `redundant_clone`, but not by this lint. |
| require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap()); |
| require_os_str(&OsString::from("x")); |
| require_path(&std::path::PathBuf::from("x")); |
| require_str(&String::from("x")); |
| require_slice(&[String::from("x")]); |
| } |
| |
| fn require_c_str(_: &CStr) {} |
| fn require_os_str(_: &OsStr) {} |
| fn require_path(_: &std::path::Path) {} |
| fn require_str(_: &str) {} |
| fn require_slice<T>(_: &[T]) {} |
| fn require_x(_: &X) {} |
| |
| fn require_deref_c_str<T: Deref<Target = CStr>>(_: T) {} |
| fn require_deref_os_str<T: Deref<Target = OsStr>>(_: T) {} |
| fn require_deref_path<T: Deref<Target = std::path::Path>>(_: T) {} |
| fn require_deref_str<T: Deref<Target = str>>(_: T) {} |
| fn require_deref_slice<T, U: Deref<Target = [T]>>(_: U) {} |
| |
| fn require_impl_deref_c_str(_: impl Deref<Target = CStr>) {} |
| fn require_impl_deref_os_str(_: impl Deref<Target = OsStr>) {} |
| fn require_impl_deref_path(_: impl Deref<Target = std::path::Path>) {} |
| fn require_impl_deref_str(_: impl Deref<Target = str>) {} |
| fn require_impl_deref_slice<T>(_: impl Deref<Target = [T]>) {} |
| |
| fn require_deref_str_slice<T: Deref<Target = str>, U, V: Deref<Target = [U]>>(_: T, _: V) {} |
| fn require_deref_slice_str<T, U: Deref<Target = [T]>, V: Deref<Target = str>>(_: U, _: V) {} |
| |
| fn require_as_ref_c_str<T: AsRef<CStr>>(_: T) {} |
| fn require_as_ref_os_str<T: AsRef<OsStr>>(_: T) {} |
| fn require_as_ref_path<T: AsRef<std::path::Path>>(_: T) {} |
| fn require_as_ref_str<T: AsRef<str>>(_: T) {} |
| fn require_as_ref_slice<T, U: AsRef<[T]>>(_: U) {} |
| |
| fn require_impl_as_ref_c_str(_: impl AsRef<CStr>) {} |
| fn require_impl_as_ref_os_str(_: impl AsRef<OsStr>) {} |
| fn require_impl_as_ref_path(_: impl AsRef<std::path::Path>) {} |
| fn require_impl_as_ref_str(_: impl AsRef<str>) {} |
| fn require_impl_as_ref_slice<T>(_: impl AsRef<[T]>) {} |
| |
| fn require_as_ref_str_slice<T: AsRef<str>, U, V: AsRef<[U]>>(_: T, _: V) {} |
| fn require_as_ref_slice_str<T, U: AsRef<[T]>, V: AsRef<str>>(_: U, _: V) {} |
| |
| // `check_files` is based on: |
| // https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 |
| fn check_files(file_types: &[FileType]) -> bool { |
| for t in file_types { |
| let path = match get_file_path(t) { |
| Ok(p) => p, |
| Err(_) => { |
| return false; |
| }, |
| }; |
| if !path.is_file() { |
| return false; |
| } |
| } |
| true |
| } |
| |
| fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> { |
| Ok(std::path::PathBuf::new()) |
| } |
| |
| fn require_string(_: &String) {} |
| |
| #[clippy::msrv = "1.35"] |
| fn _msrv_1_35() { |
| // `copied` was stabilized in 1.36, so clippy should use `cloned`. |
| let _ = &["x"][..].iter().cloned(); |
| } |
| |
| #[clippy::msrv = "1.36"] |
| fn _msrv_1_36() { |
| let _ = &["x"][..].iter().copied(); |
| } |
| |
| // https://github.com/rust-lang/rust-clippy/issues/8507 |
| mod issue_8507 { |
| #![allow(dead_code)] |
| |
| struct Opaque<P>(P); |
| |
| pub trait Abstracted {} |
| |
| impl<P> Abstracted for Opaque<P> {} |
| |
| fn build<P>(p: P) -> Opaque<P> |
| where |
| P: AsRef<str>, |
| { |
| Opaque(p) |
| } |
| |
| // Should not lint. |
| fn test_str(s: &str) -> Box<dyn Abstracted> { |
| Box::new(build(s.to_string())) |
| } |
| |
| // Should not lint. |
| fn test_x(x: super::X) -> Box<dyn Abstracted> { |
| Box::new(build(x)) |
| } |
| |
| #[derive(Clone, Copy)] |
| struct Y(&'static str); |
| |
| impl AsRef<str> for Y { |
| fn as_ref(&self) -> &str { |
| self.0 |
| } |
| } |
| |
| impl ToString for Y { |
| fn to_string(&self) -> String { |
| self.0.to_string() |
| } |
| } |
| |
| // Should lint because Y is copy. |
| fn test_y(y: Y) -> Box<dyn Abstracted> { |
| Box::new(build(y)) |
| } |
| } |
| |
| // https://github.com/rust-lang/rust-clippy/issues/8759 |
| mod issue_8759 { |
| #![allow(dead_code)] |
| |
| #[derive(Default)] |
| struct View {} |
| |
| impl std::borrow::ToOwned for View { |
| type Owned = View; |
| fn to_owned(&self) -> Self::Owned { |
| View {} |
| } |
| } |
| |
| #[derive(Default)] |
| struct RenderWindow { |
| default_view: View, |
| } |
| |
| impl RenderWindow { |
| fn default_view(&self) -> &View { |
| &self.default_view |
| } |
| fn set_view(&mut self, _view: &View) {} |
| } |
| |
| fn main() { |
| let mut rw = RenderWindow::default(); |
| rw.set_view(&rw.default_view().to_owned()); |
| } |
| } |
| |
| mod issue_8759_variant { |
| #![allow(dead_code)] |
| |
| #[derive(Clone, Default)] |
| struct View {} |
| |
| #[derive(Default)] |
| struct RenderWindow { |
| default_view: View, |
| } |
| |
| impl RenderWindow { |
| fn default_view(&self) -> &View { |
| &self.default_view |
| } |
| fn set_view(&mut self, _view: &View) {} |
| } |
| |
| fn main() { |
| let mut rw = RenderWindow::default(); |
| rw.set_view(&rw.default_view().to_owned()); |
| } |
| } |
| |
| mod issue_9317 { |
| #![allow(dead_code)] |
| |
| struct Bytes {} |
| |
| impl ToString for Bytes { |
| fn to_string(&self) -> String { |
| "123".to_string() |
| } |
| } |
| |
| impl AsRef<[u8]> for Bytes { |
| fn as_ref(&self) -> &[u8] { |
| &[1, 2, 3] |
| } |
| } |
| |
| fn consume<C: AsRef<[u8]>>(c: C) { |
| let _ = c; |
| } |
| |
| pub fn main() { |
| let b = Bytes {}; |
| // Should not lint. |
| consume(b.to_string()); |
| } |
| } |
| |
| mod issue_9351 { |
| #![allow(dead_code)] |
| |
| use std::ops::Deref; |
| use std::path::{Path, PathBuf}; |
| |
| fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T { |
| x |
| } |
| |
| fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {} |
| |
| fn id<T: AsRef<str>>(x: T) -> T { |
| x |
| } |
| |
| fn predicates_are_satisfied(_x: impl std::fmt::Write) {} |
| |
| // Should lint |
| fn single_return() -> impl AsRef<str> { |
| id("abc") |
| } |
| |
| // Should not lint |
| fn multiple_returns(b: bool) -> impl AsRef<str> { |
| if b { |
| return String::new(); |
| } |
| |
| id("abc".to_string()) |
| } |
| |
| struct S1(String); |
| |
| // Should not lint |
| fn fields1() -> S1 { |
| S1(id("abc".to_string())) |
| } |
| |
| struct S2 { |
| s: String, |
| } |
| |
| // Should not lint |
| fn fields2() { |
| let mut s = S2 { s: "abc".into() }; |
| s.s = id("abc".to_string()); |
| } |
| |
| pub fn main() { |
| let path = std::path::Path::new("x"); |
| let path_buf = path.to_owned(); |
| |
| // Should not lint. |
| let _x: PathBuf = require_deref_path(path.to_owned()); |
| generic_arg_used_elsewhere(path.to_owned(), path_buf); |
| predicates_are_satisfied(id("abc".to_string())); |
| } |
| } |
| |
| mod issue_9504 { |
| #![allow(dead_code)] |
| |
| async fn foo<S: AsRef<str>>(_: S) {} |
| async fn bar() { |
| foo(std::path::PathBuf::new().to_string_lossy().to_string()).await; |
| } |
| } |
| |
| mod issue_9771a { |
| #![allow(dead_code)] |
| |
| use std::marker::PhantomData; |
| |
| pub struct Key<K: AsRef<[u8]>, V: ?Sized>(K, PhantomData<V>); |
| |
| impl<K: AsRef<[u8]>, V: ?Sized> Key<K, V> { |
| pub fn new(key: K) -> Key<K, V> { |
| Key(key, PhantomData) |
| } |
| } |
| |
| pub fn pkh(pkh: &[u8]) -> Key<Vec<u8>, String> { |
| Key::new([b"pkh-", pkh].concat().to_vec()) |
| } |
| } |
| |
| mod issue_9771b { |
| #![allow(dead_code)] |
| |
| pub struct Key<K: AsRef<[u8]>>(K); |
| |
| pub fn from(c: &[u8]) -> Key<Vec<u8>> { |
| let v = [c].concat(); |
| Key(v.to_vec()) |
| } |
| } |
| |
| // This is a watered down version of the code in: https://github.com/oxigraph/rio |
| // The ICE is triggered by the call to `to_owned` on this line: |
| // https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116 |
| mod issue_10021 { |
| #![allow(unused)] |
| |
| pub struct Iri<T>(T); |
| |
| impl<T: AsRef<str>> Iri<T> { |
| pub fn parse(iri: T) -> Result<Self, ()> { |
| unimplemented!() |
| } |
| } |
| |
| pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> { |
| let base_iri = Iri::parse(url.to_owned())?; |
| Ok(()) |
| } |
| } |