| #![warn(clippy::double_ended_iterator_last)] | |
| // Typical case | |
| pub fn last_arg(s: &str) -> Option<&str> { | |
| s.split(' ').last() //~ double_ended_iterator_last | |
| } | |
| fn main() { | |
| // General case | |
| struct DeIterator; | |
| impl Iterator for DeIterator { | |
| type Item = (); | |
| fn next(&mut self) -> Option<Self::Item> { | |
| Some(()) | |
| } | |
| } | |
| impl DoubleEndedIterator for DeIterator { | |
| fn next_back(&mut self) -> Option<Self::Item> { | |
| Some(()) | |
| } | |
| } | |
| let _ = DeIterator.last(); //~ double_ended_iterator_last | |
| // Should not apply to other methods of Iterator | |
| let _ = DeIterator.count(); | |
| // Should not apply to simple iterators | |
| struct SimpleIterator; | |
| impl Iterator for SimpleIterator { | |
| type Item = (); | |
| fn next(&mut self) -> Option<Self::Item> { | |
| Some(()) | |
| } | |
| } | |
| let _ = SimpleIterator.last(); | |
| // Should not apply to custom implementations of last() | |
| struct CustomLast; | |
| impl Iterator for CustomLast { | |
| type Item = (); | |
| fn next(&mut self) -> Option<Self::Item> { | |
| Some(()) | |
| } | |
| fn last(self) -> Option<Self::Item> { | |
| Some(()) | |
| } | |
| } | |
| impl DoubleEndedIterator for CustomLast { | |
| fn next_back(&mut self) -> Option<Self::Item> { | |
| Some(()) | |
| } | |
| } | |
| let _ = CustomLast.last(); | |
| } | |
| // Should not be linted because applying the lint would move the original iterator. This can only be | |
| // linted if the iterator is used thereafter. | |
| fn issue_14139() { | |
| let mut index = [true, true, false, false, false, true].iter(); | |
| let subindex = index.by_ref().take(3); | |
| let _ = subindex.last(); | |
| let _ = index.next(); | |
| let mut index = [true, true, false, false, false, true].iter(); | |
| let mut subindex = index.by_ref().take(3); | |
| let _ = subindex.last(); | |
| let _ = index.next(); | |
| let mut index = [true, true, false, false, false, true].iter(); | |
| let mut subindex = index.by_ref().take(3); | |
| let subindex = &mut subindex; | |
| let _ = subindex.last(); | |
| let _ = index.next(); | |
| let mut index = [true, true, false, false, false, true].iter(); | |
| let mut subindex = index.by_ref().take(3); | |
| let subindex = &mut subindex; | |
| let _ = subindex.last(); | |
| let _ = index.next(); | |
| let mut index = [true, true, false, false, false, true].iter(); | |
| let (subindex, _) = (index.by_ref().take(3), 42); | |
| let _ = subindex.last(); | |
| let _ = index.next(); | |
| let mut index = [true, true, false, false, false, true].iter(); | |
| let subindex = (index.by_ref().take(3), 42); | |
| let _ = subindex.0.last(); | |
| let _ = index.next(); | |
| } | |
| fn drop_order() { | |
| struct DropDeIterator(std::vec::IntoIter<S>); | |
| impl Iterator for DropDeIterator { | |
| type Item = S; | |
| fn next(&mut self) -> Option<Self::Item> { | |
| self.0.next() | |
| } | |
| } | |
| impl DoubleEndedIterator for DropDeIterator { | |
| fn next_back(&mut self) -> Option<Self::Item> { | |
| self.0.next_back() | |
| } | |
| } | |
| struct S(&'static str); | |
| impl std::ops::Drop for S { | |
| fn drop(&mut self) { | |
| println!("Dropping {}", self.0); | |
| } | |
| } | |
| let v = vec![S("one"), S("two"), S("three")]; | |
| let v = DropDeIterator(v.into_iter()); | |
| println!("Last element is {}", v.last().unwrap().0); | |
| //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` | |
| let v = vec![S("four"), S("five"), S("six")]; | |
| let v = (DropDeIterator(v.into_iter()), 42); | |
| println!("Last element is {}", v.0.last().unwrap().0); | |
| //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` | |
| println!("Done"); | |
| } | |
| fn issue_14444() { | |
| let mut squares = vec![]; | |
| let last_square = [1, 2, 3] | |
| .into_iter() | |
| .map(|x| { | |
| squares.push(x * x); | |
| Some(x * x) | |
| }) | |
| .last(); | |
| } |