rust-clippy/tests/ui/methods.rs
2019-02-26 17:27:41 +01:00

386 lines
9.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// aux-build:option_helpers.rs
#![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)]
#![allow(
clippy::blacklisted_name,
unused,
clippy::print_stdout,
clippy::non_ascii_literal,
clippy::new_without_default,
clippy::missing_docs_in_private_items,
clippy::needless_pass_by_value,
clippy::default_trait_access,
clippy::use_self,
clippy::new_ret_no_self,
clippy::useless_format
)]
#[macro_use]
extern crate option_helpers;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::iter::FromIterator;
use std::ops::Mul;
use std::rc::{self, Rc};
use std::sync::{self, Arc};
use option_helpers::IteratorFalsePositives;
pub struct T;
impl T {
pub fn add(self, other: T) -> T {
self
}
// no error, not public interface
pub(crate) fn drop(&mut self) {}
// no error, private function
fn neg(self) -> Self {
self
}
// no error, private function
fn eq(&self, other: T) -> bool {
true
}
// no error, self is a ref
fn sub(&self, other: T) -> &T {
self
}
// no error, different #arguments
fn div(self) -> T {
self
}
fn rem(self, other: T) {} // no error, wrong return type
// fine
fn into_u32(self) -> u32 {
0
}
fn into_u16(&self) -> u16 {
0
}
fn to_something(self) -> u32 {
0
}
fn new(self) -> Self {
unimplemented!();
}
}
struct Lt<'a> {
foo: &'a u32,
}
impl<'a> Lt<'a> {
// The lifetime is different, but thats irrelevant, see #734
#[allow(clippy::needless_lifetimes)]
pub fn new<'b>(s: &'b str) -> Lt<'b> {
unimplemented!()
}
}
struct Lt2<'a> {
foo: &'a u32,
}
impl<'a> Lt2<'a> {
// The lifetime is different, but thats irrelevant, see #734
pub fn new(s: &str) -> Lt2 {
unimplemented!()
}
}
struct Lt3<'a> {
foo: &'a u32,
}
impl<'a> Lt3<'a> {
// The lifetime is different, but thats irrelevant, see #734
pub fn new() -> Lt3<'static> {
unimplemented!()
}
}
#[derive(Clone, Copy)]
struct U;
impl U {
fn new() -> Self {
U
}
// ok because U is Copy
fn to_something(self) -> u32 {
0
}
}
struct V<T> {
_dummy: T,
}
impl<T> V<T> {
fn new() -> Option<V<T>> {
None
}
}
impl Mul<T> for T {
type Output = T;
// no error, obviously
fn mul(self, other: T) -> T {
self
}
}
/// Checks implementation of the following lints:
/// * `OPTION_MAP_UNWRAP_OR`
/// * `OPTION_MAP_UNWRAP_OR_ELSE`
/// * `OPTION_MAP_OR_NONE`
#[rustfmt::skip]
fn option_methods() {
let opt = Some(1);
// Check OPTION_MAP_UNWRAP_OR
// single line case
let _ = opt.map(|x| x + 1)
.unwrap_or(0); // should lint even though this call is on a separate line
// multi line cases
let _ = opt.map(|x| {
x + 1
}
).unwrap_or(0);
let _ = opt.map(|x| x + 1)
.unwrap_or({
0
});
// single line `map(f).unwrap_or(None)` case
let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
// multiline `map(f).unwrap_or(None)` cases
let _ = opt.map(|x| {
Some(x + 1)
}
).unwrap_or(None);
let _ = opt
.map(|x| Some(x + 1))
.unwrap_or(None);
// macro case
let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint
// Should not lint if not copyable
let id: String = "identifier".to_string();
let _ = Some("prefix").map(|p| format!("{}.{}", p, id)).unwrap_or(id);
// ...but DO lint if the `unwrap_or` argument is not used in the `map`
let id: String = "identifier".to_string();
let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
// Check OPTION_MAP_UNWRAP_OR_ELSE
// single line case
let _ = opt.map(|x| x + 1)
.unwrap_or_else(|| 0); // should lint even though this call is on a separate line
// multi line cases
let _ = opt.map(|x| {
x + 1
}
).unwrap_or_else(|| 0);
let _ = opt.map(|x| x + 1)
.unwrap_or_else(||
0
);
// macro case
let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint
// Check OPTION_MAP_OR_NONE
// single line case
let _ = opt.map_or(None, |x| Some(x + 1));
// multi line case
let _ = opt.map_or(None, |x| {
Some(x + 1)
}
);
}
/// Struct to generate false positives for things with .iter()
#[derive(Copy, Clone)]
struct HasIter;
impl HasIter {
fn iter(self) -> IteratorFalsePositives {
IteratorFalsePositives { foo: 0 }
}
fn iter_mut(self) -> IteratorFalsePositives {
IteratorFalsePositives { foo: 0 }
}
}
/// Checks implementation of `FILTER_NEXT` lint
#[rustfmt::skip]
fn filter_next() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
// check single-line case
let _ = v.iter().filter(|&x| *x < 0).next();
// check multi-line case
let _ = v.iter().filter(|&x| {
*x < 0
}
).next();
// check that we don't lint if the caller is not an Iterator
let foo = IteratorFalsePositives { foo: 0 };
let _ = foo.filter().next();
}
/// Checks implementation of `SEARCH_IS_SOME` lint
#[rustfmt::skip]
fn search_is_some() {
let v = vec![3, 2, 1, 0, -1, -2, -3];
// check `find().is_some()`, single-line
let _ = v.iter().find(|&x| *x < 0).is_some();
// check `find().is_some()`, multi-line
let _ = v.iter().find(|&x| {
*x < 0
}
).is_some();
// check `position().is_some()`, single-line
let _ = v.iter().position(|&x| x < 0).is_some();
// check `position().is_some()`, multi-line
let _ = v.iter().position(|&x| {
x < 0
}
).is_some();
// check `rposition().is_some()`, single-line
let _ = v.iter().rposition(|&x| x < 0).is_some();
// check `rposition().is_some()`, multi-line
let _ = v.iter().rposition(|&x| {
x < 0
}
).is_some();
// check that we don't lint if the caller is not an Iterator
let foo = IteratorFalsePositives { foo: 0 };
let _ = foo.find().is_some();
let _ = foo.position().is_some();
let _ = foo.rposition().is_some();
}
/// Checks implementation of the `OR_FUN_CALL` lint
fn or_fun_call() {
struct Foo;
impl Foo {
fn new() -> Foo {
Foo
}
}
enum Enum {
A(i32),
}
fn make<T>() -> T {
unimplemented!();
}
let with_enum = Some(Enum::A(1));
with_enum.unwrap_or(Enum::A(5));
let with_const_fn = Some(::std::time::Duration::from_secs(1));
with_const_fn.unwrap_or(::std::time::Duration::from_secs(5));
let with_constructor = Some(vec![1]);
with_constructor.unwrap_or(make());
let with_new = Some(vec![1]);
with_new.unwrap_or(Vec::new());
let with_const_args = Some(vec![1]);
with_const_args.unwrap_or(Vec::with_capacity(12));
let with_err: Result<_, ()> = Ok(vec![1]);
with_err.unwrap_or(make());
let with_err_args: Result<_, ()> = Ok(vec![1]);
with_err_args.unwrap_or(Vec::with_capacity(12));
let with_default_trait = Some(1);
with_default_trait.unwrap_or(Default::default());
let with_default_type = Some(1);
with_default_type.unwrap_or(u64::default());
let with_vec = Some(vec![1]);
with_vec.unwrap_or(vec![]);
// FIXME #944: ~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);
let without_default = Some(Foo);
without_default.unwrap_or(Foo::new());
let mut map = HashMap::<u64, String>::new();
map.entry(42).or_insert(String::new());
let mut btree = BTreeMap::<u64, String>::new();
btree.entry(42).or_insert(String::new());
let stringy = Some(String::from(""));
let _ = stringy.unwrap_or("".to_owned());
}
/// Checks implementation of `ITER_NTH` lint
fn iter_nth() {
let mut some_vec = vec![0, 1, 2, 3];
let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
{
// Make sure we lint `.iter()` for relevant types
let bad_vec = some_vec.iter().nth(3);
let bad_slice = &some_vec[..].iter().nth(3);
let bad_boxed_slice = boxed_slice.iter().nth(3);
let bad_vec_deque = some_vec_deque.iter().nth(3);
}
{
// Make sure we lint `.iter_mut()` for relevant types
let bad_vec = some_vec.iter_mut().nth(3);
}
{
let bad_slice = &some_vec[..].iter_mut().nth(3);
}
{
let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
}
// Make sure we don't lint for non-relevant types
let false_positive = HasIter;
let ok = false_positive.iter().nth(3);
let ok_mut = false_positive.iter_mut().nth(3);
}
#[allow(clippy::similar_names)]
fn main() {
let opt = Some(0);
let _ = opt.unwrap();
}