#![warn(clippy::str_split_at_newline)] use core::str::Split; use std::ops::Deref; struct NotStr<'a> { s: &'a str, } impl<'a> NotStr<'a> { fn trim(&'a self) -> &'a str { self.s } } struct DerefsIntoNotStr<'a> { not_str: &'a NotStr<'a>, } impl<'a> Deref for DerefsIntoNotStr<'a> { type Target = NotStr<'a>; fn deref(&self) -> &Self::Target { self.not_str } } struct DerefsIntoStr<'a> { s: &'a str, } impl<'a> Deref for DerefsIntoStr<'a> { type Target = str; fn deref(&self) -> &Self::Target { self.s } } macro_rules! trim_split { ( $x:expr, $y:expr ) => { $x.trim().split($y); }; } macro_rules! make_str { ( $x: expr ) => { format!("x={}", $x) }; } fn main() { let s1 = "hello\nworld\n"; let s2 = s1.to_owned(); // CASES THAT SHOULD EMIT A LINT // Splitting a `str` variable at "\n" or "\r\n" after trimming should warn let _ = s1.trim().split('\n'); #[allow(clippy::single_char_pattern)] let _ = s1.trim().split("\n"); let _ = s1.trim().split("\r\n"); // Splitting a `String` variable at "\n" or "\r\n" after trimming should warn let _ = s2.trim().split('\n'); #[allow(clippy::single_char_pattern)] let _ = s2.trim().split("\n"); let _ = s2.trim().split("\r\n"); // Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn. let s3 = DerefsIntoStr { s: s1 }; let _ = s3.trim().split('\n'); #[allow(clippy::single_char_pattern)] let _ = s3.trim().split("\n"); let _ = s3.trim().split("\r\n"); // If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix. let _ = make_str!(s1).trim().split('\n'); // CASES THAT SHOULD NOT EMIT A LINT // Splitting a `str` constant at "\n" or "\r\n" after trimming should not warn let _ = "hello\nworld\n".trim().split('\n'); #[allow(clippy::single_char_pattern)] let _ = "hello\nworld\n".trim().split("\n"); let _ = "hello\nworld\n".trim().split("\r\n"); // Splitting a `str` variable at "\n" or "\r\n" without trimming should not warn, since it is not // equivalent let _ = s1.split('\n'); #[allow(clippy::single_char_pattern)] let _ = s1.split("\n"); let _ = s1.split("\r\n"); // Splitting a `String` variable at "\n" or "\r\n" without trimming should not warn. let _ = s2.split('\n'); #[allow(clippy::single_char_pattern)] let _ = s2.split("\n"); // Splitting a variable that derefs into `str` at "\n" or "\r\n" without trimming should not warn. let _ = s3.split('\n'); #[allow(clippy::single_char_pattern)] let _ = s3.split("\n"); let _ = s3.split("\r\n"); let _ = s2.split("\r\n"); // Splitting a `str` variable at other separators should not warn let _ = s1.trim().split('\r'); #[allow(clippy::single_char_pattern)] let _ = s1.trim().split("\r"); let _ = s1.trim().split("\n\r"); let _ = s1.trim().split("\r \n"); // Splitting a `String` variable at other separators should not warn let _ = s2.trim().split('\r'); #[allow(clippy::single_char_pattern)] let _ = s2.trim().split("\r"); let _ = s2.trim().split("\n\r"); // Splitting a variable that derefs into `str` at other separators should not warn let _ = s3.trim().split('\r'); #[allow(clippy::single_char_pattern)] let _ = s3.trim().split("\r"); let _ = s3.trim().split("\n\r"); let _ = s3.trim().split("\r \n"); let _ = s2.trim().split("\r \n"); // Using `trim` and `split` on other types should not warn let not_str = NotStr { s: s1 }; let _ = not_str.trim().split('\n'); #[allow(clippy::single_char_pattern)] let _ = not_str.trim().split("\n"); let _ = not_str.trim().split("\r\n"); let derefs_into_not_str = DerefsIntoNotStr { not_str: ¬_str }; let _ = derefs_into_not_str.trim().split('\n'); #[allow(clippy::single_char_pattern)] let _ = derefs_into_not_str.trim().split("\n"); let _ = derefs_into_not_str.trim().split("\r\n"); // Code generated by macros should not create a warning trim_split!(s1, "\r\n"); trim_split!("hello\nworld\n", "\r\n"); trim_split!(s2, "\r\n"); trim_split!(s3, "\r\n"); }