summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/methods/mod.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /src/tools/clippy/clippy_lints/src/methods/mod.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/methods/mod.rs')
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs307
1 files changed, 191 insertions, 116 deletions
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 8a76ba0b0..d2913680c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -54,6 +54,7 @@ mod map_flatten;
mod map_identity;
mod map_unwrap_or;
mod mut_mutex_lock;
+mod needless_collect;
mod needless_option_as_deref;
mod needless_option_take;
mod no_effect_replace;
@@ -69,6 +70,8 @@ mod path_buf_push_overwrite;
mod range_zip_with_len;
mod repeat_once;
mod search_is_some;
+mod seek_from_current;
+mod seek_to_start_instead_of_rewind;
mod single_char_add_str;
mod single_char_insert_string;
mod single_char_pattern;
@@ -101,17 +104,16 @@ mod zst_offset;
use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
-use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
+use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, TraitRef, Ty};
-use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
@@ -156,9 +158,9 @@ declare_clippy_lint! {
/// ```
/// Use instead:
/// ```rust
- /// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+ /// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");
/// ```
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub COLLAPSIBLE_STR_REPLACE,
perf,
"collapse consecutive calls to str::replace (2 or more) into a single call"
@@ -829,32 +831,30 @@ declare_clippy_lint! {
/// etc. instead.
///
/// ### Why is this bad?
- /// The function will always be called and potentially
- /// allocate an object acting as the default.
+ /// The function will always be called. This is only bad if it allocates or
+ /// does some non-trivial amount of work.
///
/// ### Known problems
- /// If the function has side-effects, not calling it will
- /// change the semantic of the program, but you shouldn't rely on that anyway.
+ /// If the function has side-effects, not calling it will change the
+ /// semantic of the program, but you shouldn't rely on that.
+ ///
+ /// The lint also cannot figure out whether the function you call is
+ /// actually expensive to call or not.
///
/// ### Example
/// ```rust
/// # let foo = Some(String::new());
- /// foo.unwrap_or(String::new());
+ /// foo.unwrap_or(String::from("empty"));
/// ```
///
/// Use instead:
/// ```rust
/// # let foo = Some(String::new());
- /// foo.unwrap_or_else(String::new);
- ///
- /// // or
- ///
- /// # let foo = Some(String::new());
- /// foo.unwrap_or_default();
+ /// foo.unwrap_or_else(|| String::from("empty"));
/// ```
#[clippy::version = "pre 1.29.0"]
pub OR_FUN_CALL,
- perf,
+ nursery,
"using any `*or` method with a function call, which suggests `*or_else`"
}
@@ -1728,7 +1728,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
+ /// Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str).
///
/// ### Why is this bad?
/// Readability, this can be written more concisely as
@@ -2094,8 +2094,7 @@ declare_clippy_lint! {
/// let s = "Hello world!";
/// let cow = Cow::Borrowed(s);
///
- /// let data = cow.into_owned();
- /// assert!(matches!(data, String))
+ /// let _data: String = cow.into_owned();
/// ```
#[clippy::version = "1.65.0"]
pub SUSPICIOUS_TO_OWNED,
@@ -2426,7 +2425,7 @@ declare_clippy_lint! {
/// ### Known problems
///
/// The type of the resulting iterator might become incompatible with its usage
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub ITER_ON_SINGLE_ITEMS,
nursery,
"Iterator for array of length 1"
@@ -2458,7 +2457,7 @@ declare_clippy_lint! {
/// ### Known problems
///
/// The type of the resulting iterator might become incompatible with its usage
- #[clippy::version = "1.64.0"]
+ #[clippy::version = "1.65.0"]
pub ITER_ON_EMPTY_COLLECTIONS,
nursery,
"Iterator for empty array"
@@ -3066,9 +3065,105 @@ declare_clippy_lint! {
"iterating on map using `iter` when `keys` or `values` would do"
}
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks an argument of `seek` method of `Seek` trait
+ /// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Readability. Use dedicated method.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// use std::io::{self, Write, Seek, SeekFrom};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello")?;
+ /// eprintln!("Written {} bytes", f.seek(SeekFrom::Current(0))?);
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust,no_run
+ /// use std::fs::File;
+ /// use std::io::{self, Write, Seek, SeekFrom};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::create("foo.txt")?;
+ /// f.write_all(b"Hello")?;
+ /// eprintln!("Written {} bytes", f.stream_position()?);
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub SEEK_FROM_CURRENT,
+ complexity,
+ "use dedicated method for seek from current position"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for jumps to the start of a stream that implements `Seek`
+ /// and uses the `seek` method providing `Start` as parameter.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Readability. There is a specific method that was implemented for
+ /// this exact scenario.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::io;
+ /// fn foo<T: io::Seek>(t: &mut T) {
+ /// t.seek(io::SeekFrom::Start(0));
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::io;
+ /// fn foo<T: io::Seek>(t: &mut T) {
+ /// t.rewind();
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub SEEK_TO_START_INSTEAD_OF_REWIND,
+ complexity,
+ "jumping to the start of stream using `seek` method"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for functions collecting an iterator when collect
+ /// is not needed.
+ ///
+ /// ### Why is this bad?
+ /// `collect` causes the allocation of a new data structure,
+ /// when this allocation may not be needed.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let iterator = vec![1].into_iter();
+ /// let len = iterator.clone().collect::<Vec<_>>().len();
+ /// // should be
+ /// let len = iterator.count();
+ /// ```
+ #[clippy::version = "1.30.0"]
+ pub NEEDLESS_COLLECT,
+ nursery,
+ "collecting an iterator when collect is not needed"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
}
@@ -3077,7 +3172,7 @@ impl Methods {
#[must_use]
pub fn new(
avoid_breaking_exported_api: bool,
- msrv: Option<RustcVersion>,
+ msrv: Msrv,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
) -> Self {
@@ -3190,16 +3285,19 @@ impl_lint_pass!(Methods => [
VEC_RESIZE_TO_ZERO,
VERBOSE_FILE_READS,
ITER_KV_MAP,
+ SEEK_FROM_CURRENT,
+ SEEK_TO_START_INSTEAD_OF_REWIND,
+ NEEDLESS_COLLECT,
]);
/// Extracts a method call name, args, and `Span` of the method name.
fn method_call<'tcx>(
recv: &'tcx hir::Expr<'tcx>,
-) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
- if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
+) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
+ if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
let name = path.ident.name.as_str();
- return Some((name, receiver, args, path.ident.span));
+ return Some((name, receiver, args, path.ident.span, call_span));
}
}
None
@@ -3227,7 +3325,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
single_char_add_str::check(cx, expr, receiver, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
- unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
+ unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv);
},
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo {
@@ -3316,36 +3414,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
let ret_ty = return_ty(cx, impl_item.hir_id());
- // walk the return type and check for Self (this does not check associated types)
- if let Some(self_adt) = self_ty.ty_adt_def() {
- if contains_adt_constructor(ret_ty, self_adt) {
- return;
- }
- } else if ret_ty.contains(self_ty) {
+ if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
return;
}
- // if return type is impl trait, check the associated types
- if let ty::Opaque(def_id, _) = *ret_ty.kind() {
- // one of the associated types must be Self
- for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
- if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
- let assoc_ty = match projection_predicate.term.unpack() {
- ty::TermKind::Ty(ty) => ty,
- ty::TermKind::Const(_c) => continue,
- };
- // walk the associated type and check for Self
- if let Some(self_adt) = self_ty.ty_adt_def() {
- if contains_adt_constructor(assoc_ty, self_adt) {
- return;
- }
- } else if assoc_ty.contains(self_ty) {
- return;
- }
- }
- }
- }
-
if name == "new" && ret_ty != self_ty {
span_lint(
cx,
@@ -3411,7 +3483,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
impl Methods {
#[allow(clippy::too_many_lines)]
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let Some((name, recv, args, span)) = method_call(expr) {
+ if let Some((name, recv, args, span, call_span)) = method_call(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
zst_offset::check(cx, expr, recv);
@@ -3429,29 +3501,32 @@ impl Methods {
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
- ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
- ("collect", []) => match method_call(recv) {
- Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
- iter_cloned_collect::check(cx, name, expr, recv2);
- },
- Some(("map", m_recv, [m_arg], _)) => {
- map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
- },
- Some(("take", take_self_arg, [take_arg], _)) => {
- if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
- manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
- }
- },
- _ => {},
+ ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
+ ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
+ needless_collect::check(cx, span, expr, recv, call_span);
+ match method_call(recv) {
+ Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
+ iter_cloned_collect::check(cx, name, expr, recv2);
+ },
+ Some(("map", m_recv, [m_arg], _, _)) => {
+ map_collect_result_unit::check(cx, expr, m_recv, m_arg);
+ },
+ Some(("take", take_self_arg, [take_arg], _, _)) => {
+ if self.msrv.meets(msrvs::STR_REPEAT) {
+ manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+ }
+ },
+ _ => {},
+ }
},
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
- Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
- Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
+ Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
iter_count::check(cx, expr, recv2, name2);
},
- Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
- Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
- Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+ Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
+ Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
+ Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
_ => {},
},
("drain", [arg]) => {
@@ -3463,8 +3538,8 @@ impl Methods {
}
},
("expect", [_]) => match method_call(recv) {
- Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
- Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
+ Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
+ Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
},
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
@@ -3484,13 +3559,13 @@ impl Methods {
flat_map_option::check(cx, expr, arg, span);
},
("flatten", []) => match method_call(recv) {
- Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
- Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
+ Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
- if let Some(("inspect", _, [_], span2)) = method_call(recv) {
+ if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
@@ -3503,19 +3578,19 @@ impl Methods {
unit_hash::check(cx, expr, recv, arg);
},
("is_file", []) => filetype_is_file::check(cx, expr, recv),
- ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
+ ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
("iter" | "iter_mut" | "into_iter", []) => {
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
},
("join", [join_arg]) => {
- if let Some(("collect", _, _, span)) = method_call(recv) {
+ if let Some(("collect", _, _, span, _)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", []) | ("skip", [_]) => {
- if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
@@ -3526,17 +3601,17 @@ impl Methods {
},
(name @ ("map" | "map_err"), [m_arg]) => {
if name == "map" {
- map_clone::check(cx, expr, recv, m_arg, self.msrv);
- if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _)) = method_call(recv) {
+ map_clone::check(cx, expr, recv, m_arg, &self.msrv);
+ if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
}
} else {
map_err_ignore::check(cx, expr, m_arg);
}
- if let Some((name, recv2, args, span2)) = method_call(recv) {
+ if let Some((name, recv2, args, span2,_)) = method_call(recv) {
match (name, args) {
- ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
- ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
+ ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv),
+ ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv),
("filter", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
@@ -3553,11 +3628,11 @@ impl Methods {
manual_ok_or::check(cx, expr, recv, def, map);
},
("next", []) => {
- if let Some((name2, recv2, args2, _)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
- ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
+ ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr),
@@ -3566,10 +3641,10 @@ impl Methods {
}
},
("nth", [n_arg]) => match method_call(recv) {
- Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
- Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
- Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
- Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+ Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
+ Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+ Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
@@ -3604,6 +3679,14 @@ impl Methods {
("resize", [count_arg, default_arg]) => {
vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
},
+ ("seek", [arg]) => {
+ if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) {
+ seek_from_current::check(cx, expr, recv, arg);
+ }
+ if self.msrv.meets(msrvs::SEEK_REWIND) {
+ seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
+ }
+ },
("sort", []) => {
stable_sort_primitive::check(cx, expr, recv);
},
@@ -3616,7 +3699,7 @@ impl Methods {
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
- str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
+ str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
}
},
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
@@ -3626,7 +3709,7 @@ impl Methods {
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [_arg]) => {
- if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
@@ -3634,7 +3717,7 @@ impl Methods {
},
("take", []) => needless_option_take::check(cx, expr, recv),
("then", [arg]) => {
- if !meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+ if !self.msrv.meets(msrvs::BOOL_THEN_SOME) {
return;
}
unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
@@ -3649,13 +3732,13 @@ impl Methods {
},
("unwrap", []) => {
match method_call(recv) {
- Some(("get", recv, [get_arg], _)) => {
+ Some(("get", recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
- Some(("get_mut", recv, [get_arg], _)) => {
+ Some(("get_mut", recv, [get_arg], _, _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
- Some(("or", recv, [or_arg], or_span)) => {
+ Some(("or", recv, [or_arg], or_span, _)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
@@ -3664,20 +3747,20 @@ impl Methods {
},
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
("unwrap_or", [u_arg]) => match method_call(recv) {
- Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
+ Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
- Some(("map", m_recv, [m_arg], span)) => {
+ Some(("map", m_recv, [m_arg], span, _)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
- Some(("then_some", t_recv, [t_arg], _)) => {
+ Some(("then_some", t_recv, [t_arg], _, _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
- Some(("map", recv, [map_arg], _))
- if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
+ Some(("map", recv, [map_arg], _, _))
+ if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
@@ -3697,7 +3780,7 @@ impl Methods {
}
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
- if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
+ if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) = method_call(recv) {
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}
@@ -3906,14 +3989,6 @@ impl OutType {
}
}
-fn is_bool(ty: &hir::Ty<'_>) -> bool {
- if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
- matches!(path.res, Res::PrimTy(PrimTy::Bool))
- } else {
- false
- }
-}
-
fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
expected.constness == actual.constness
&& expected.unsafety == actual.unsafety