diff options
Diffstat (limited to 'src/tools/clippy/tests/ui/unnecessary_to_owned.rs')
-rw-r--r-- | src/tools/clippy/tests/ui/unnecessary_to_owned.rs | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs new file mode 100644 index 000000000..fe09a489a --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs @@ -0,0 +1,331 @@ +// run-rustfix + +#![allow(clippy::ptr_arg)] +#![warn(clippy::unnecessary_to_owned)] +#![feature(custom_inner_attributes)] + +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).into_owned()); + require_c_str(&c_str.to_owned()); + + require_os_str(&os_str.to_os_string()); + require_os_str(&Cow::from(os_str).into_owned()); + require_os_str(&os_str.to_owned()); + + require_path(&path.to_path_buf()); + require_path(&Cow::from(path).into_owned()); + require_path(&path.to_owned()); + + require_str(&s.to_string()); + require_str(&Cow::from(s).into_owned()); + require_str(&s.to_owned()); + require_str(&x_ref.to_string()); + + require_slice(&slice.to_vec()); + require_slice(&Cow::from(slice).into_owned()); + require_slice(&array.to_owned()); + require_slice(&array_ref.to_owned()); + require_slice(&slice.to_owned()); + require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. + + require_x(&Cow::<X>::Owned(x.clone()).into_owned()); + require_x(&x_ref.to_owned()); // No longer flagged because of #8759. + + require_deref_c_str(c_str.to_owned()); + require_deref_os_str(os_str.to_owned()); + require_deref_path(path.to_owned()); + require_deref_str(s.to_owned()); + require_deref_slice(slice.to_owned()); + + require_impl_deref_c_str(c_str.to_owned()); + require_impl_deref_os_str(os_str.to_owned()); + require_impl_deref_path(path.to_owned()); + require_impl_deref_str(s.to_owned()); + require_impl_deref_slice(slice.to_owned()); + + require_deref_str_slice(s.to_owned(), slice.to_owned()); + require_deref_slice_str(slice.to_owned(), s.to_owned()); + + require_as_ref_c_str(c_str.to_owned()); + require_as_ref_os_str(os_str.to_owned()); + require_as_ref_path(path.to_owned()); + require_as_ref_str(s.to_owned()); + require_as_ref_str(x.to_owned()); + require_as_ref_slice(array.to_owned()); + require_as_ref_slice(array_ref.to_owned()); + require_as_ref_slice(slice.to_owned()); + + require_impl_as_ref_c_str(c_str.to_owned()); + require_impl_as_ref_os_str(os_str.to_owned()); + require_impl_as_ref_path(path.to_owned()); + require_impl_as_ref_str(s.to_owned()); + require_impl_as_ref_str(x.to_owned()); + require_impl_as_ref_slice(array.to_owned()); + require_impl_as_ref_slice(array_ref.to_owned()); + require_impl_as_ref_slice(slice.to_owned()); + + require_as_ref_str_slice(s.to_owned(), array.to_owned()); + require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); + require_as_ref_str_slice(s.to_owned(), slice.to_owned()); + require_as_ref_slice_str(array.to_owned(), s.to_owned()); + require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); + require_as_ref_slice_str(slice.to_owned(), s.to_owned()); + + let _ = x.join(&x_ref.to_string()); + + let _ = slice.to_vec().into_iter(); + let _ = slice.to_owned().into_iter(); + let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); + let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); + + let _ = IntoIterator::into_iter(slice.to_vec()); + let _ = IntoIterator::into_iter(slice.to_owned()); + let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); + let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); + + 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().to_owned()); + require_os_str(&OsString::from("x").to_os_string()); + require_path(&std::path::PathBuf::from("x").to_path_buf()); + require_str(&String::from("x").to_string()); + require_slice(&[String::from("x")].to_owned()); +} + +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.to_vec() { + 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) {} + +fn _msrv_1_35() { + #![clippy::msrv = "1.35"] + // `copied` was stabilized in 1.36, so clippy should use `cloned`. + let _ = &["x"][..].to_vec().into_iter(); +} + +fn _msrv_1_36() { + #![clippy::msrv = "1.36"] + let _ = &["x"][..].to_vec().into_iter(); +} + +// 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.to_string())) + } +} + +// 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()); + } +} |